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