device-manager: Fix the writing of the database when priority doesn't change.
[profile/ivi/pulseaudio.git] / 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 and prioritise by role");
59 PA_MODULE_VERSION(PACKAGE_VERSION);
60 PA_MODULE_LOAD_ONCE(TRUE);
61 PA_MODULE_USAGE(
62     "do_routing=<Automatically route streams based on a priority list (unique per-role)?> "
63     "on_hotplug=<When new device becomes available, recheck streams?> "
64     "on_rescue=<When device becomes unavailable, recheck streams?>");
65
66 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
67 #define DUMP_DATABASE
68
69 static const char* const valid_modargs[] = {
70     "do_routing",
71     "on_hotplug",
72     "on_rescue",
73     NULL
74 };
75
76 #define NUM_ROLES 9
77 enum {
78     ROLE_NONE,
79     ROLE_VIDEO,
80     ROLE_MUSIC,
81     ROLE_GAME,
82     ROLE_EVENT,
83     ROLE_PHONE,
84     ROLE_ANIMATION,
85     ROLE_PRODUCTION,
86     ROLE_A11Y,
87 };
88
89 typedef uint32_t role_indexes_t[NUM_ROLES];
90
91 static const char* role_names[NUM_ROLES] = {
92     "none",
93     "video",
94     "music",
95     "game",
96     "event",
97     "phone",
98     "animation",
99     "production",
100     "a11y",
101 };
102
103 struct userdata {
104     pa_core *core;
105     pa_module *module;
106     pa_subscription *subscription;
107     pa_hook_slot
108         *sink_new_hook_slot,
109         *source_new_hook_slot,
110         *sink_input_new_hook_slot,
111         *source_output_new_hook_slot,
112         *sink_put_hook_slot,
113         *source_put_hook_slot,
114         *sink_unlink_hook_slot,
115         *source_unlink_hook_slot,
116         *connection_unlink_hook_slot;
117     pa_time_event *save_time_event;
118     pa_database *database;
119
120     pa_native_protocol *protocol;
121     pa_idxset *subscribed;
122
123     pa_bool_t on_hotplug;
124     pa_bool_t on_rescue;
125     pa_bool_t do_routing;
126
127     role_indexes_t preferred_sinks;
128     role_indexes_t preferred_sources;
129 };
130
131 #define ENTRY_VERSION 1
132
133 struct entry {
134     uint8_t version;
135     char description[PA_NAME_MAX];
136     char icon[PA_NAME_MAX];
137     role_indexes_t priority;
138 } PA_GCC_PACKED;
139
140 enum {
141     SUBCOMMAND_TEST,
142     SUBCOMMAND_READ,
143     SUBCOMMAND_RENAME,
144     SUBCOMMAND_DELETE,
145     SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
146     SUBCOMMAND_REORDER,
147     SUBCOMMAND_SUBSCRIBE,
148     SUBCOMMAND_EVENT
149 };
150
151
152 static struct entry* read_entry(struct userdata *u, const char *name) {
153     pa_datum key, data;
154     struct entry *e;
155
156     pa_assert(u);
157     pa_assert(name);
158
159     key.data = (char*) name;
160     key.size = strlen(name);
161
162     pa_zero(data);
163
164     if (!pa_database_get(u->database, &key, &data))
165         goto fail;
166
167     if (data.size != sizeof(struct entry)) {
168         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));
169         goto fail;
170     }
171
172     e = (struct entry*) data.data;
173
174     if (e->version != ENTRY_VERSION) {
175         pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name);
176         goto fail;
177     }
178
179     if (!memchr(e->description, 0, sizeof(e->description))) {
180         pa_log_warn("Database contains entry for device %s with missing NUL byte in description", name);
181         goto fail;
182     }
183
184     return e;
185
186 fail:
187
188     pa_datum_free(&data);
189     return NULL;
190 }
191
192 #ifdef DUMP_DATABASE
193 static void dump_database_helper(struct userdata *u, uint32_t role_index, const char* human, pa_bool_t sink_mode) {
194     pa_assert(u);
195     pa_assert(human);
196
197     if (sink_mode) {
198         pa_sink *s;
199         if (PA_INVALID_INDEX != u->preferred_sinks[role_index] && (s = pa_idxset_get_by_index(u->core->sinks, u->preferred_sinks[role_index])))
200             pa_log_debug("   %s %s (%s)", human, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION)), s->name);
201         else
202             pa_log_debug("   %s No sink specified", human);
203     } else {
204         pa_source *s;
205         if (PA_INVALID_INDEX != u->preferred_sinks[role_index] && (s = pa_idxset_get_by_index(u->core->sinks, u->preferred_sinks[role_index])))
206             pa_log_debug("   %s %s (%s)", human, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION)), s->name);
207         else
208             pa_log_debug("   %s No source specified", human);
209     }
210 }
211
212 static void dump_database(struct userdata *u) {
213     pa_datum key;
214     pa_bool_t done;
215
216     pa_assert(u);
217
218     done = !pa_database_first(u->database, &key, NULL);
219
220     pa_log_debug("Dumping database");
221     while (!done) {
222         char *name;
223         struct entry *e;
224         pa_datum next_key;
225
226         done = !pa_database_next(u->database, &key, &next_key, NULL);
227
228         name = pa_xstrndup(key.data, key.size);
229
230         if ((e = read_entry(u, name))) {
231             pa_log_debug(" Got entry: %s", name);
232             pa_log_debug("  Description: %s", e->description);
233             pa_log_debug("  Priorities: None:   %3u, Video: %3u, Music:  %3u, Game: %3u, Event: %3u",
234                          e->priority[ROLE_NONE], e->priority[ROLE_VIDEO], e->priority[ROLE_MUSIC], e->priority[ROLE_GAME], e->priority[ROLE_EVENT]);
235             pa_log_debug("              Phone:  %3u, Anim:  %3u, Prodtn: %3u, A11y: %3u",
236                          e->priority[ROLE_PHONE], e->priority[ROLE_ANIMATION], e->priority[ROLE_PRODUCTION], e->priority[ROLE_A11Y]);
237             pa_xfree(e);
238         }
239
240         pa_xfree(name);
241
242         pa_datum_free(&key);
243         key = next_key;
244     }
245
246     pa_log_debug(" Highest priority devices per-role:");
247
248     pa_log_debug("  Sinks:");
249     for (uint32_t role = ROLE_NONE; role < NUM_ROLES; ++role) {
250         char name[13];
251         uint32_t len = PA_MIN(12u, strlen(role_names[role]));
252         strncpy(name, role_names[role], len);
253         for (int i = len+1; i < 12; ++i) name[i] = ' ';
254         name[len] = ':'; name[0] -= 32; name[12] = '\0';
255         dump_database_helper(u, role, name, TRUE);
256     }
257
258     pa_log_debug("  Sources:");
259     for (uint32_t role = ROLE_NONE; role < NUM_ROLES; ++role) {
260         char name[13];
261         uint32_t len = PA_MIN(12u, strlen(role_names[role]));
262         strncpy(name, role_names[role], len);
263         for (int i = len+1; i < 12; ++i) name[i] = ' ';
264         name[len] = ':'; name[0] -= 32; name[12] = '\0';
265         dump_database_helper(u, role, name, FALSE);
266     }
267
268     pa_log_debug("Completed database dump");
269 }
270 #endif
271
272 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
273     struct userdata *u = userdata;
274
275     pa_assert(a);
276     pa_assert(e);
277     pa_assert(u);
278
279     pa_assert(e == u->save_time_event);
280     u->core->mainloop->time_free(u->save_time_event);
281     u->save_time_event = NULL;
282
283     pa_database_sync(u->database);
284     pa_log_info("Synced.");
285
286 #ifdef DUMP_DATABASE
287     dump_database(u);
288 #endif
289 }
290
291 static void notify_subscribers(struct userdata *u) {
292
293     pa_native_connection *c;
294     uint32_t idx;
295
296     pa_assert(u);
297
298     for (c = pa_idxset_first(u->subscribed, &idx); c; c = pa_idxset_next(u->subscribed, &idx)) {
299         pa_tagstruct *t;
300
301         t = pa_tagstruct_new(NULL, 0);
302         pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
303         pa_tagstruct_putu32(t, 0);
304         pa_tagstruct_putu32(t, u->module->index);
305         pa_tagstruct_puts(t, u->module->name);
306         pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
307
308         pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
309     }
310 }
311
312 static void trigger_save(struct userdata *u) {
313
314     pa_assert(u);
315
316     notify_subscribers(u);
317
318     if (u->save_time_event)
319         return;
320
321     u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
322 }
323
324 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
325
326     pa_assert(a);
327     pa_assert(b);
328
329     if (strncmp(a->description, b->description, sizeof(a->description))
330         || strncmp(a->icon, b->icon, sizeof(a->icon)))
331         return FALSE;
332
333     for (int i=0; i < NUM_ROLES; ++i)
334         if (a->priority[i] != b->priority[i])
335             return FALSE;
336
337     return TRUE;
338 }
339
340 static char *get_name(const char *key, const char *prefix) {
341     char *t;
342
343     if (strncmp(key, prefix, strlen(prefix)))
344         return NULL;
345
346     t = pa_xstrdup(key + strlen(prefix));
347     return t;
348 }
349
350 static inline struct entry *load_or_initialize_entry(struct userdata *u, struct entry *entry, const char *name, const char *prefix) {
351     struct entry *old;
352
353     pa_assert(u);
354     pa_assert(entry);
355     pa_assert(name);
356     pa_assert(prefix);
357
358     if ((old = read_entry(u, name)))
359         *entry = *old;
360     else {
361         /* This is a new device, so make sure we write it's priority list correctly */
362         role_indexes_t max_priority;
363         pa_datum key;
364         pa_bool_t done;
365
366         pa_zero(max_priority);
367         done = !pa_database_first(u->database, &key, NULL);
368
369         /* Find all existing devices with the same prefix so we calculate the current max priority for each role */
370         while (!done) {
371             pa_datum next_key;
372
373             done = !pa_database_next(u->database, &key, &next_key, NULL);
374
375             if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
376                 char *name2;
377                 struct entry *e;
378
379                 name2 = pa_xstrndup(key.data, key.size);
380
381                 if ((e = read_entry(u, name2))) {
382                     for (uint32_t i = 0; i < NUM_ROLES; ++i) {
383                         max_priority[i] = PA_MAX(max_priority[i], e->priority[i]);
384                     }
385
386                     pa_xfree(e);
387                 }
388
389                 pa_xfree(name2);
390             }
391             pa_datum_free(&key);
392             key = next_key;
393         }
394
395         /* Actually initialise our entry now we've calculated it */
396         for (uint32_t i = 0; i < NUM_ROLES; ++i) {
397             entry->priority[i] = max_priority[i] + 1;
398         }
399     }
400
401     return old;
402 }
403
404 static uint32_t get_role_index(const char* role) {
405     pa_assert(role);
406
407     for (uint32_t i = ROLE_NONE; i < NUM_ROLES; ++i)
408         if (strcmp(role, role_names[i]) == 0)
409             return i;
410
411     return PA_INVALID_INDEX;
412 }
413
414 static void update_highest_priority_device_indexes(struct userdata *u, const char *prefix, void *ignore_device) {
415     role_indexes_t *indexes, highest_priority_available;
416     pa_datum key;
417     pa_bool_t done, sink_mode;
418
419     pa_assert(u);
420     pa_assert(prefix);
421
422     sink_mode = (strcmp(prefix, "sink:") == 0);
423
424     if (sink_mode)
425         indexes = &u->preferred_sinks;
426     else
427         indexes = &u->preferred_sources;
428
429     for (uint32_t i = 0; i < NUM_ROLES; ++i) {
430         *indexes[i] = PA_INVALID_INDEX;
431     }
432     pa_zero(highest_priority_available);
433
434     done = !pa_database_first(u->database, &key, NULL);
435
436     /* Find all existing devices with the same prefix so we find the highest priority device for each role */
437     while (!done) {
438         pa_datum next_key;
439
440         done = !pa_database_next(u->database, &key, &next_key, NULL);
441
442         if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
443             char *name;
444             struct entry *e;
445
446             name = pa_xstrndup(key.data, key.size);
447
448             if ((e = read_entry(u, name))) {
449                 for (uint32_t i = 0; i < NUM_ROLES; ++i) {
450                     if (highest_priority_available[i] && e->priority[i] < highest_priority_available[i]) {
451                         /* We've found a device with a higher priority than that we've currently got,
452                            so see if it is currently available or not and update our list */
453                         uint32_t idx;
454                         pa_bool_t found = FALSE;
455                         char *device_name = get_name(name, prefix);
456
457                         if (sink_mode) {
458                             pa_sink *sink;
459
460                             PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
461                                 if ((pa_sink*) ignore_device == sink)
462                                     continue;
463                                 if (strcmp(sink->name, device_name) == 0) {
464                                     found = TRUE;
465                                     idx = sink->index; /* Is this needed? */
466                                     break;
467                                 }
468                             }
469                         } else {
470                             pa_source *source;
471
472                             PA_IDXSET_FOREACH(source, u->core->sources, idx) {
473                                 if ((pa_source*) ignore_device == source)
474                                     continue;
475                                 if (strcmp(source->name, device_name) == 0) {
476                                     found = TRUE;
477                                     idx = source->index; /* Is this needed? */
478                                     break;
479                                 }
480                             }
481                         }
482                         if (found) {
483                             highest_priority_available[i] = e->priority[i];
484                             *indexes[i] = idx;
485                         }
486
487                         pa_xfree(device_name);
488                     }
489                 }
490
491                 pa_xfree(e);
492             }
493
494             pa_xfree(name);
495         }
496
497         pa_datum_free(&key);
498         key = next_key;
499     }
500 }
501
502
503 static void route_sink_input(struct userdata *u, pa_sink_input *si) {
504     const char *role;
505     uint32_t role_index, device_index;
506     pa_sink *sink;
507
508     pa_assert(u);
509     pa_assert(u->do_routing);
510
511     if (si->save_sink)
512         return;
513
514     /* Skip this if it is already in the process of being moved anyway */
515     if (!si->sink)
516         return;
517
518     /* It might happen that a stream and a sink are set up at the
519     same time, in which case we want to make sure we don't
520     interfere with that */
521     if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
522         return;
523
524     if (!(role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE)))
525         role_index = get_role_index("none");
526     else
527         role_index = get_role_index(role);
528
529     if (PA_INVALID_INDEX == role_index)
530         return;
531
532     device_index = u->preferred_sinks[role_index];
533     if (PA_INVALID_INDEX == device_index)
534         return;
535
536     if (!(sink = pa_idxset_get_by_index(u->core->sinks, device_index)))
537         return;
538
539     if (si->sink != sink)
540         pa_sink_input_move_to(si, sink, TRUE);
541 }
542
543 static pa_hook_result_t route_sink_inputs(struct userdata *u, pa_sink *ignore_sink) {
544     pa_sink_input *si;
545     uint32_t idx;
546
547     pa_assert(u);
548
549     if (!u->do_routing)
550         return PA_HOOK_OK;
551
552     update_highest_priority_device_indexes(u, "sink:", ignore_sink);
553
554     PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
555         route_sink_input(u, si);
556     }
557
558     return PA_HOOK_OK;
559 }
560
561 static void route_source_output(struct userdata *u, pa_source_output *so) {
562     const char *role;
563     uint32_t role_index, device_index;
564     pa_source *source;
565
566     pa_assert(u);
567     pa_assert(u->do_routing);
568
569     if (so->save_source)
570         return;
571
572     if (so->direct_on_input)
573         return;
574
575     /* Skip this if it is already in the process of being moved anyway */
576     if (!so->source)
577         return;
578
579     /* It might happen that a stream and a source are set up at the
580     same time, in which case we want to make sure we don't
581     interfere with that */
582     if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
583         return;
584
585     if (!(role = pa_proplist_gets(so->proplist, PA_PROP_MEDIA_ROLE)))
586         role_index = get_role_index("none");
587     else
588         role_index = get_role_index(role);
589
590     if (PA_INVALID_INDEX == role_index)
591         return;
592
593     device_index = u->preferred_sources[role_index];
594     if (PA_INVALID_INDEX == device_index)
595         return;
596
597     if (!(source = pa_idxset_get_by_index(u->core->sources, device_index)))
598         return;
599
600     if (so->source != source)
601         pa_source_output_move_to(so, source, TRUE);
602 }
603
604 static pa_hook_result_t route_source_outputs(struct userdata *u, pa_source* ignore_source) {
605     pa_source_output *so;
606     uint32_t idx;
607
608     pa_assert(u);
609
610     if (!u->do_routing)
611         return PA_HOOK_OK;
612
613     update_highest_priority_device_indexes(u, "source:", ignore_source);
614
615     PA_IDXSET_FOREACH(so, u->core->source_outputs, idx) {
616         route_source_output(u, so);
617     }
618
619     return PA_HOOK_OK;
620 }
621
622 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
623     struct userdata *u = userdata;
624     struct entry entry, *old = NULL;
625     char *name = NULL;
626     pa_datum key, data;
627
628     pa_assert(c);
629     pa_assert(u);
630
631     if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
632         t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
633         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
634         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE) &&
635
636         /*t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) &&*/
637         t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
638         /*t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW) &&*/
639         t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE))
640         return;
641
642     pa_zero(entry);
643     entry.version = ENTRY_VERSION;
644
645     if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
646         pa_sink_input *si;
647
648         if (!u->do_routing)
649             return;
650         if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx)))
651             return;
652
653         /* The role may change mid-stream, so we reroute */
654         route_sink_input(u, si);
655
656         return;
657     } else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT) {
658         pa_source_output *so;
659
660         if (!u->do_routing)
661             return;
662         if (!(so = pa_idxset_get_by_index(c->source_outputs, idx)))
663             return;
664
665         /* The role may change mid-stream, so we reroute */
666         route_source_output(u, so);
667
668         return;
669     } else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
670         pa_sink *sink;
671
672         if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
673             return;
674
675         name = pa_sprintf_malloc("sink:%s", sink->name);
676
677         old = load_or_initialize_entry(u, &entry, name, "sink:");
678
679         pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
680         pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
681
682     } else  if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) {
683         pa_source *source;
684
685         pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
686
687         if (!(source = pa_idxset_get_by_index(c->sources, idx)))
688             return;
689
690         if (source->monitor_of)
691             return;
692
693         name = pa_sprintf_malloc("source:%s", source->name);
694
695         old = load_or_initialize_entry(u, &entry, name, "source:");
696
697         pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
698         pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
699     }
700
701     pa_assert(name);
702
703     if (old) {
704
705         if (entries_equal(old, &entry)) {
706             pa_xfree(old);
707             pa_xfree(name);
708
709             return;
710         }
711
712         pa_xfree(old);
713     }
714
715     key.data = name;
716     key.size = strlen(name);
717
718     data.data = &entry;
719     data.size = sizeof(entry);
720
721     pa_log_info("Storing device %s.", name);
722
723     pa_database_set(u->database, &key, &data, TRUE);
724
725     pa_xfree(name);
726
727     trigger_save(u);
728 }
729
730 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
731     char *name;
732     struct entry *e;
733
734     pa_assert(c);
735     pa_assert(new_data);
736     pa_assert(u);
737
738     name = pa_sprintf_malloc("sink:%s", new_data->name);
739
740     if ((e = read_entry(u, name))) {
741         if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
742             pa_log_info("Restoring description for sink %s.", new_data->name);
743             pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
744         }
745
746         pa_xfree(e);
747     }
748
749     pa_xfree(name);
750
751     return PA_HOOK_OK;
752 }
753
754 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
755     char *name;
756     struct entry *e;
757
758     pa_assert(c);
759     pa_assert(new_data);
760     pa_assert(u);
761
762     name = pa_sprintf_malloc("source:%s", new_data->name);
763
764     if ((e = read_entry(u, name))) {
765         if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
766             /* NB, We cannot detect if we are a monitor here... this could mess things up a bit... */
767             pa_log_info("Restoring description for source %s.", new_data->name);
768             pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
769         }
770
771         pa_xfree(e);
772     }
773
774     pa_xfree(name);
775
776     return PA_HOOK_OK;
777 }
778
779 static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
780     pa_assert(c);
781     pa_assert(new_data);
782     pa_assert(u);
783
784     if (!u->do_routing)
785         return PA_HOOK_OK;
786
787     if (new_data->sink)
788         pa_log_debug("Not restoring device for stream, because already set.");
789     else {
790         const char *role;
791         uint32_t role_index;
792
793         if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE)))
794             role_index = get_role_index("");
795         else
796             role_index = get_role_index(role);
797
798         if (PA_INVALID_INDEX != role_index) {
799             uint32_t device_index;
800
801             device_index = u->preferred_sinks[role_index];
802             if (PA_INVALID_INDEX != device_index) {
803                 pa_sink *sink;
804
805                 if ((sink = pa_idxset_get_by_index(u->core->sinks, device_index))) {
806                     new_data->sink = sink;
807                     new_data->save_sink = TRUE;
808                 }
809             }
810         }
811     }
812
813     return PA_HOOK_OK;
814 }
815
816 static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
817     pa_assert(c);
818     pa_assert(new_data);
819     pa_assert(u);
820
821     if (!u->do_routing)
822         return PA_HOOK_OK;
823
824     if (new_data->direct_on_input)
825         return PA_HOOK_OK;
826
827     if (new_data->source)
828         pa_log_debug("Not restoring device for stream, because already set");
829     else {
830         const char *role;
831         uint32_t role_index;
832
833         if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE)))
834             role_index = get_role_index("");
835         else
836             role_index = get_role_index(role);
837
838         if (PA_INVALID_INDEX != role_index) {
839             uint32_t device_index;
840
841             device_index = u->preferred_sources[role_index];
842             if (PA_INVALID_INDEX != device_index) {
843                 pa_source *source;
844
845                 if ((source = pa_idxset_get_by_index(u->core->sources, device_index))) {
846                     new_data->source = source;
847                     new_data->save_source = TRUE;
848                 }
849             }
850         }
851     }
852
853     return PA_HOOK_OK;
854 }
855
856
857 static pa_hook_result_t sink_put_hook_callback(pa_core *c, PA_GCC_UNUSED pa_sink *sink, struct userdata *u) {
858     pa_assert(c);
859     pa_assert(u);
860     pa_assert(u->core == c);
861     pa_assert(u->on_hotplug);
862
863     notify_subscribers(u);
864
865     return route_sink_inputs(u, NULL);
866 }
867
868 static pa_hook_result_t source_put_hook_callback(pa_core *c, PA_GCC_UNUSED pa_source *source, struct userdata *u) {
869     pa_assert(c);
870     pa_assert(u);
871     pa_assert(u->core == c);
872     pa_assert(u->on_hotplug);
873
874     notify_subscribers(u);
875
876     return route_source_outputs(u, NULL);
877 }
878
879 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
880     pa_assert(c);
881     pa_assert(sink);
882     pa_assert(u);
883     pa_assert(u->core == c);
884     pa_assert(u->on_rescue);
885
886     /* There's no point in doing anything if the core is shut down anyway */
887     if (c->state == PA_CORE_SHUTDOWN)
888         return PA_HOOK_OK;
889
890     notify_subscribers(u);
891
892     return route_sink_inputs(u, sink);
893 }
894
895 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
896     pa_assert(c);
897     pa_assert(source);
898     pa_assert(u);
899     pa_assert(u->core == c);
900     pa_assert(u->on_rescue);
901
902     /* There's no point in doing anything if the core is shut down anyway */
903     if (c->state == PA_CORE_SHUTDOWN)
904         return PA_HOOK_OK;
905
906     notify_subscribers(u);
907
908     return route_source_outputs(u, source);
909 }
910
911
912 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
913     pa_sink *sink;
914     pa_source *source;
915     uint32_t idx;
916     char *n;
917
918     pa_assert(u);
919     pa_assert(name);
920     pa_assert(e);
921
922     if ((n = get_name(name, "sink:"))) {
923         for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) {
924             if (!pa_streq(sink->name, n)) {
925                 continue;
926             }
927
928             pa_log_info("Setting description for sink %s.", sink->name);
929             pa_sink_set_description(sink, e->description);
930         }
931         pa_xfree(n);
932     }
933     else if ((n = get_name(name, "source:"))) {
934         for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) {
935             if (!pa_streq(source->name, n)) {
936                 continue;
937             }
938
939             if (source->monitor_of) {
940                 pa_log_warn("Cowardly refusing to set the description for monitor source %s.", source->name);
941                 continue;
942             }
943
944             pa_log_info("Setting description for source %s.", source->name);
945             pa_source_set_description(source, e->description);
946         }
947         pa_xfree(n);
948     }
949 }
950
951
952 #define EXT_VERSION 1
953
954 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
955   struct userdata *u;
956   uint32_t command;
957   pa_tagstruct *reply = NULL;
958
959   pa_assert(p);
960   pa_assert(m);
961   pa_assert(c);
962   pa_assert(t);
963
964   u = m->userdata;
965
966   if (pa_tagstruct_getu32(t, &command) < 0)
967     goto fail;
968
969   reply = pa_tagstruct_new(NULL, 0);
970   pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
971   pa_tagstruct_putu32(reply, tag);
972
973   switch (command) {
974     case SUBCOMMAND_TEST: {
975       if (!pa_tagstruct_eof(t))
976         goto fail;
977
978       pa_tagstruct_putu32(reply, EXT_VERSION);
979       break;
980     }
981
982     case SUBCOMMAND_READ: {
983       pa_datum key;
984       pa_bool_t done;
985
986       if (!pa_tagstruct_eof(t))
987         goto fail;
988
989       done = !pa_database_first(u->database, &key, NULL);
990
991       while (!done) {
992         pa_datum next_key;
993         struct entry *e;
994         char *name;
995
996         done = !pa_database_next(u->database, &key, &next_key, NULL);
997
998         name = pa_xstrndup(key.data, key.size);
999         pa_datum_free(&key);
1000
1001         if ((e = read_entry(u, name))) {
1002             uint32_t idx;
1003             char *devname;
1004             pa_bool_t available = FALSE;
1005
1006             if ((devname = get_name(name, "sink:"))) {
1007                 pa_sink* s;
1008                 PA_IDXSET_FOREACH(s, u->core->sinks, idx) {
1009                     if (strcmp(s->name, devname) == 0) {
1010                         available = TRUE;
1011                         break;
1012                     }
1013                 }
1014                 pa_xfree(devname);
1015             } else if ((devname = get_name(name, "source:"))) {
1016                 pa_source* s;
1017                 PA_IDXSET_FOREACH(s, u->core->sources, idx) {
1018                     if (strcmp(s->name, devname) == 0) {
1019                         available = TRUE;
1020                         break;
1021                     }
1022                 }
1023                 pa_xfree(devname);
1024             }
1025
1026             pa_tagstruct_puts(reply, name);
1027             pa_tagstruct_puts(reply, e->description);
1028             pa_tagstruct_puts(reply, e->icon);
1029             pa_tagstruct_put_boolean(reply, available);
1030             pa_tagstruct_putu32(reply, NUM_ROLES);
1031
1032             for (uint32_t i = ROLE_NONE; i < NUM_ROLES; ++i) {
1033                 pa_tagstruct_puts(reply, role_names[i]);
1034                 pa_tagstruct_putu32(reply, e->priority[i]);
1035             }
1036
1037             pa_xfree(e);
1038         }
1039
1040         pa_xfree(name);
1041
1042         key = next_key;
1043       }
1044
1045       break;
1046     }
1047
1048     case SUBCOMMAND_RENAME: {
1049
1050         struct entry *e;
1051         const char *device, *description;
1052
1053         if (pa_tagstruct_gets(t, &device) < 0 ||
1054           pa_tagstruct_gets(t, &description) < 0)
1055           goto fail;
1056
1057         if (!device || !*device || !description || !*description)
1058           goto fail;
1059
1060         if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
1061             pa_datum key, data;
1062
1063             pa_strlcpy(e->description, description, sizeof(e->description));
1064
1065             key.data = (char *) device;
1066             key.size = strlen(device);
1067
1068             data.data = e;
1069             data.size = sizeof(*e);
1070
1071             if (pa_database_set(u->database, &key, &data, TRUE) == 0) {
1072                 apply_entry(u, device, e);
1073
1074                 trigger_save(u);
1075             }
1076             else
1077                 pa_log_warn("Could not save device");
1078
1079             pa_xfree(e);
1080         }
1081         else
1082             pa_log_warn("Could not rename device %s, no entry in database", device);
1083
1084       break;
1085     }
1086
1087     case SUBCOMMAND_DELETE:
1088
1089       while (!pa_tagstruct_eof(t)) {
1090         const char *name;
1091         pa_datum key;
1092
1093         if (pa_tagstruct_gets(t, &name) < 0)
1094           goto fail;
1095
1096         key.data = (char*) name;
1097         key.size = strlen(name);
1098
1099         /** @todo: Reindex the priorities */
1100         pa_database_unset(u->database, &key);
1101       }
1102
1103       trigger_save(u);
1104
1105       break;
1106
1107     case SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING: {
1108
1109         pa_bool_t enable;
1110
1111         if (pa_tagstruct_get_boolean(t, &enable) < 0)
1112             goto fail;
1113
1114         if ((u->do_routing = enable)) {
1115             /* Update our caches */
1116             update_highest_priority_device_indexes(u, "sink:", NULL);
1117             update_highest_priority_device_indexes(u, "source:", NULL);
1118         }
1119
1120         break;
1121     }
1122
1123     case SUBCOMMAND_REORDER: {
1124
1125         const char *role;
1126         struct entry *e;
1127         uint32_t role_index, n_devices;
1128         pa_datum key, data;
1129         pa_bool_t done, sink_mode = TRUE;
1130         struct device_t { uint32_t prio; char *device; };
1131         struct device_t *device;
1132         struct device_t **devices;
1133         uint32_t i, idx, offset;
1134         pa_hashmap *h;
1135         void *state;
1136         pa_bool_t first;
1137
1138         if (pa_tagstruct_gets(t, &role) < 0 ||
1139             pa_tagstruct_getu32(t, &n_devices) < 0 ||
1140             n_devices < 1)
1141             goto fail;
1142
1143         if (PA_INVALID_INDEX == (role_index = get_role_index(role)))
1144            goto fail;
1145
1146         /* Cycle through the devices given and make sure they exist */
1147         h = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1148         first = TRUE;
1149         idx = 0;
1150         for (i = 0; i < n_devices; ++i) {
1151             const char *s;
1152             if (pa_tagstruct_gets(t, &s) < 0) {
1153                 while ((device = pa_hashmap_steal_first(h))) {
1154                     pa_xfree(device->device);
1155                     pa_xfree(device);
1156                 }
1157
1158                 pa_hashmap_free(h, NULL, NULL);
1159                 pa_log_error("Protocol error on reorder");
1160                 goto fail;
1161             }
1162
1163             /* Ensure this is a valid entry */
1164             if (!(e = read_entry(u, s))) {
1165                 while ((device = pa_hashmap_steal_first(h))) {
1166                     pa_xfree(device->device);
1167                     pa_xfree(device);
1168                 }
1169
1170                 pa_hashmap_free(h, NULL, NULL);
1171                 pa_log_error("Client specified an unknown device in it's reorder list.");
1172                 goto fail;
1173             }
1174             pa_xfree(e);
1175
1176             if (first) {
1177                 first = FALSE;
1178                 sink_mode = (0 == strncmp("sink:", s, 5));
1179             } else if ((sink_mode && 0 != strncmp("sink:", s, 5))
1180                        || (!sink_mode && 0 != strncmp("source:", s, 7)))
1181             {
1182                 while ((device = pa_hashmap_steal_first(h))) {
1183                     pa_xfree(device->device);
1184                     pa_xfree(device);
1185                 }
1186
1187                 pa_hashmap_free(h, NULL, NULL);
1188                 pa_log_error("Attempted to reorder mixed devices (sinks and sources)");
1189                 goto fail;
1190             }
1191
1192             /* Add the device to our hashmap. If it's alredy in it, free it now and carry on */
1193             device = pa_xnew(struct device_t, 1);
1194             device->device = pa_xstrdup(s);
1195             if (pa_hashmap_put(h, device->device, device) == 0) {
1196                 device->prio = idx;
1197                 idx++;
1198             } else {
1199                 pa_xfree(device->device);
1200                 pa_xfree(device);
1201             }
1202         }
1203
1204         pa_log_debug("Hashmap contents (received from client)");
1205         PA_HASHMAP_FOREACH(device, h, state) {
1206             pa_log_debug("  - %s (%d)", device->device, device->prio);
1207         }
1208
1209         /* Now cycle through our list and add all the devices.
1210            This has the effect of addign in any in our DB,
1211            not specified in the device list (and thus will be
1212            tacked on at the end) */
1213         offset = idx;
1214         done = !pa_database_first(u->database, &key, NULL);
1215
1216         while (!done && idx < 256) {
1217             pa_datum next_key;
1218
1219             done = !pa_database_next(u->database, &key, &next_key, NULL);
1220
1221             device = pa_xnew(struct device_t, 1);
1222             device->device = pa_xstrndup(key.data, key.size);
1223             if ((sink_mode && 0 == strncmp("sink:", device->device, 5))
1224                 || (!sink_mode && 0 == strncmp("source:", device->device, 7))) {
1225
1226                 /* Add the device to our hashmap. If it's alredy in it, free it now and carry on */
1227                 if (pa_hashmap_put(h, device->device, device) == 0
1228                     && (e = read_entry(u, device->device)) && ENTRY_VERSION == e->version) {
1229                     /* We add offset on to the existing priorirty so that when we order, the
1230                        existing entries are always lower priority than the new ones. */
1231                     device->prio = (offset + e->priority[role_index]);
1232                     pa_xfree(e);
1233                 }
1234                 else {
1235                     pa_xfree(device->device);
1236                     pa_xfree(device);
1237                 }
1238             } else {
1239                 pa_xfree(device->device);
1240                 pa_xfree(device);
1241             }
1242
1243             pa_datum_free(&key);
1244
1245             key = next_key;
1246         }
1247
1248         pa_log_debug("Hashmap contents (combined with database)");
1249         PA_HASHMAP_FOREACH(device, h, state) {
1250             pa_log_debug("  - %s (%d)", device->device, device->prio);
1251         }
1252
1253         /* Now we put all the entries in a simple list for sorting it. */
1254         n_devices = pa_hashmap_size(h);
1255         devices = pa_xnew(struct device_t *,  n_devices);
1256         idx = 0;
1257         while ((device = pa_hashmap_steal_first(h))) {
1258             devices[idx++] = device;
1259         }
1260         pa_hashmap_free(h, NULL, NULL);
1261
1262         /* Simple bubble sort */
1263         for (i = 0; i < n_devices; ++i) {
1264             for (uint32_t j = i; j < n_devices; ++j) {
1265                 if (devices[i]->prio > devices[j]->prio) {
1266                     struct device_t *tmp;
1267                     tmp = devices[i];
1268                     devices[i] = devices[j];
1269                     devices[j] = tmp;
1270                 }
1271             }
1272         }
1273
1274         pa_log_debug("Sorted device list");
1275         for (i = 0; i < n_devices; ++i) {
1276             pa_log_debug("  - %s (%d)", devices[i]->device, devices[i]->prio);
1277         }
1278
1279         /* Go through in order and write the new entry and cleanup our own list */
1280         idx = 1;
1281         first = TRUE;
1282         for (i = 0; i < n_devices; ++i) {
1283             if ((e = read_entry(u, devices[i]->device)) && ENTRY_VERSION == e->version) {
1284                 if (e->priority[role_index] == idx)
1285                     idx++;
1286                 else {
1287                     e->priority[role_index] = idx;
1288
1289                     key.data = (char *) devices[i]->device;
1290                     key.size = strlen(devices[i]->device);
1291
1292                     data.data = e;
1293                     data.size = sizeof(*e);
1294
1295                     pa_log_debug("Attempting to write record: %d. %s", e->priority[role_index], e->description);
1296                     if (pa_database_set(u->database, &key, &data, TRUE) == 0) {
1297                         pa_log_debug("..... write successfull");
1298                         first = FALSE;
1299                         idx++;
1300                     }
1301                 }
1302
1303                 pa_xfree(e);
1304             }
1305             pa_xfree(devices[i]->device);
1306             pa_xfree(devices[i]);
1307         }
1308
1309         if (!first)
1310             trigger_save(u);
1311
1312         break;
1313     }
1314
1315     case SUBCOMMAND_SUBSCRIBE: {
1316
1317       pa_bool_t enabled;
1318
1319       if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1320         !pa_tagstruct_eof(t))
1321         goto fail;
1322
1323       if (enabled)
1324         pa_idxset_put(u->subscribed, c, NULL);
1325       else
1326         pa_idxset_remove_by_data(u->subscribed, c, NULL);
1327
1328       break;
1329     }
1330
1331     default:
1332       goto fail;
1333   }
1334
1335   pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1336   return 0;
1337
1338   fail:
1339
1340   if (reply)
1341     pa_tagstruct_free(reply);
1342
1343   return -1;
1344 }
1345
1346 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
1347     pa_assert(p);
1348     pa_assert(c);
1349     pa_assert(u);
1350
1351     pa_idxset_remove_by_data(u->subscribed, c, NULL);
1352     return PA_HOOK_OK;
1353 }
1354
1355 int pa__init(pa_module*m) {
1356     pa_modargs *ma = NULL;
1357     struct userdata *u;
1358     char *fname;
1359     pa_sink *sink;
1360     pa_source *source;
1361     uint32_t idx;
1362     pa_bool_t do_routing = FALSE, on_hotplug = TRUE, on_rescue = TRUE;
1363
1364     pa_assert(m);
1365
1366     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1367         pa_log("Failed to parse module arguments");
1368         goto fail;
1369     }
1370
1371     if (pa_modargs_get_value_boolean(ma, "do_routing", &do_routing) < 0 ||
1372         pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
1373         pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
1374         pa_log("on_hotplug= and on_rescue= expect boolean arguments");
1375         goto fail;
1376     }
1377
1378     m->userdata = u = pa_xnew0(struct userdata, 1);
1379     u->core = m->core;
1380     u->module = m;
1381     u->do_routing = do_routing;
1382     u->on_hotplug = on_hotplug;
1383     u->on_rescue = on_rescue;
1384     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1385
1386     u->protocol = pa_native_protocol_get(m->core);
1387     pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1388
1389     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);
1390
1391     u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
1392
1393     /* Used to handle device description management */
1394     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);
1395     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);
1396
1397     /* The following slots are used to deal with routing */
1398     /* A little bit later than module-stream-restore, module-intended-roles */
1399     u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY+15, (pa_hook_cb_t) sink_input_new_hook_callback, u);
1400     u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY+15, (pa_hook_cb_t) source_output_new_hook_callback, u);
1401
1402     if (on_hotplug) {
1403         /* A little bit later than module-stream-restore, module-intended-roles */
1404         u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+15, (pa_hook_cb_t) sink_put_hook_callback, u);
1405         u->source_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+15, (pa_hook_cb_t) source_put_hook_callback, u);
1406     }
1407
1408     if (on_rescue) {
1409         /* A little bit later than module-stream-restore, module-intended-roles, a little bit earlier than module-rescue-streams, ... */
1410         u->sink_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+15, (pa_hook_cb_t) sink_unlink_hook_callback, u);
1411         u->source_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+15, (pa_hook_cb_t) source_unlink_hook_callback, u);
1412     }
1413
1414     if (!(fname = pa_state_path("device-manager", TRUE)))
1415         goto fail;
1416
1417     if (!(u->database = pa_database_open(fname, TRUE))) {
1418         pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
1419         pa_xfree(fname);
1420         goto fail;
1421     }
1422
1423     pa_log_info("Sucessfully opened database file '%s'.", fname);
1424     pa_xfree(fname);
1425
1426     /* We cycle over all the available sinks so that they are added to our database if they are not in it yet */
1427     PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
1428         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
1429
1430     PA_IDXSET_FOREACH(source, m->core->sources, idx)
1431         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
1432
1433     /* Perform the routing (if it's enabled) which will update our priority list cache too */
1434     route_sink_inputs(u, NULL);
1435     route_source_outputs(u, NULL);
1436
1437 #ifdef DUMP_DATABASE
1438     dump_database(u);
1439 #endif
1440
1441     pa_modargs_free(ma);
1442     return 0;
1443
1444 fail:
1445     pa__done(m);
1446
1447     if (ma)
1448         pa_modargs_free(ma);
1449
1450     return  -1;
1451 }
1452
1453 void pa__done(pa_module*m) {
1454     struct userdata* u;
1455
1456     pa_assert(m);
1457
1458     if (!(u = m->userdata))
1459         return;
1460
1461     if (u->subscription)
1462         pa_subscription_free(u->subscription);
1463
1464     if (u->sink_new_hook_slot)
1465         pa_hook_slot_free(u->sink_new_hook_slot);
1466     if (u->source_new_hook_slot)
1467         pa_hook_slot_free(u->source_new_hook_slot);
1468
1469     if (u->sink_input_new_hook_slot)
1470         pa_hook_slot_free(u->sink_input_new_hook_slot);
1471     if (u->source_output_new_hook_slot)
1472         pa_hook_slot_free(u->source_output_new_hook_slot);
1473
1474     if (u->sink_put_hook_slot)
1475         pa_hook_slot_free(u->sink_put_hook_slot);
1476     if (u->source_put_hook_slot)
1477         pa_hook_slot_free(u->source_put_hook_slot);
1478
1479     if (u->sink_unlink_hook_slot)
1480         pa_hook_slot_free(u->sink_unlink_hook_slot);
1481     if (u->source_unlink_hook_slot)
1482         pa_hook_slot_free(u->source_unlink_hook_slot);
1483
1484     if (u->save_time_event)
1485         u->core->mainloop->time_free(u->save_time_event);
1486
1487     if (u->database)
1488         pa_database_close(u->database);
1489
1490     if (u->protocol) {
1491         pa_native_protocol_remove_ext(u->protocol, m);
1492         pa_native_protocol_unref(u->protocol);
1493     }
1494
1495     if (u->subscribed)
1496         pa_idxset_free(u->subscribed, NULL, NULL);
1497
1498     pa_xfree(u);
1499 }