device-manager: Misc fixes.
[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_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     if (si->save_sink)
514         return;
515
516     /* Skip this if it is already in the process of being moved anyway */
517     if (!si->sink)
518         return;
519
520     /* It might happen that a stream and a sink are set up at the
521     same time, in which case we want to make sure we don't
522     interfere with that */
523     if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
524         return;
525
526     if (!(role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE)))
527         role_index = get_role_index("none");
528     else
529         role_index = get_role_index(role);
530
531     if (PA_INVALID_INDEX == role_index)
532         return;
533
534     device_index = u->preferred_sinks[role_index];
535     if (PA_INVALID_INDEX == device_index)
536         return;
537
538     if (!(sink = pa_idxset_get_by_index(u->core->sinks, device_index)))
539         return;
540
541     if (si->sink != sink)
542         pa_sink_input_move_to(si, sink, TRUE);
543 }
544
545 static pa_hook_result_t route_sink_inputs(struct userdata *u, pa_sink *ignore_sink) {
546     pa_sink_input *si;
547     uint32_t idx;
548
549     pa_assert(u);
550
551     if (!u->do_routing)
552         return PA_HOOK_OK;
553
554     update_highest_priority_device_indexes(u, "sink:", ignore_sink);
555
556     PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
557         route_sink_input(u, si);
558     }
559
560     return PA_HOOK_OK;
561 }
562
563 static void route_source_output(struct userdata *u, pa_source_output *so) {
564     const char *role;
565     uint32_t role_index, device_index;
566     pa_source *source;
567
568     pa_assert(u);
569     pa_assert(u->do_routing);
570
571     if (so->save_source)
572         return;
573
574     if (so->direct_on_input)
575         return;
576
577     /* Skip this if it is already in the process of being moved anyway */
578     if (!so->source)
579         return;
580
581     /* It might happen that a stream and a source are set up at the
582     same time, in which case we want to make sure we don't
583     interfere with that */
584     if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
585         return;
586
587     if (!(role = pa_proplist_gets(so->proplist, PA_PROP_MEDIA_ROLE)))
588         role_index = get_role_index("none");
589     else
590         role_index = get_role_index(role);
591
592     if (PA_INVALID_INDEX == role_index)
593         return;
594
595     device_index = u->preferred_sources[role_index];
596     if (PA_INVALID_INDEX == device_index)
597         return;
598
599     if (!(source = pa_idxset_get_by_index(u->core->sources, device_index)))
600         return;
601
602     if (so->source != source)
603         pa_source_output_move_to(so, source, TRUE);
604 }
605
606 static pa_hook_result_t route_source_outputs(struct userdata *u, pa_source* ignore_source) {
607     pa_source_output *so;
608     uint32_t idx;
609
610     pa_assert(u);
611
612     if (!u->do_routing)
613         return PA_HOOK_OK;
614
615     update_highest_priority_device_indexes(u, "source:", ignore_source);
616
617     PA_IDXSET_FOREACH(so, u->core->source_outputs, idx) {
618         route_source_output(u, so);
619     }
620
621     return PA_HOOK_OK;
622 }
623
624 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
625     struct userdata *u = userdata;
626     struct entry entry, *old = NULL;
627     char *name = NULL;
628     pa_datum key, data;
629
630     pa_assert(c);
631     pa_assert(u);
632
633     if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
634         t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
635         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
636         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE) &&
637
638         /*t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) &&*/
639         t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
640         /*t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW) &&*/
641         t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE))
642         return;
643
644     pa_zero(entry);
645     entry.version = ENTRY_VERSION;
646
647     if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
648         pa_sink_input *si;
649
650         if (!u->do_routing)
651             return;
652         if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx)))
653             return;
654
655         /* The role may change mid-stream, so we reroute */
656         route_sink_input(u, si);
657
658         return;
659     } else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT) {
660         pa_source_output *so;
661
662         if (!u->do_routing)
663             return;
664         if (!(so = pa_idxset_get_by_index(c->source_outputs, idx)))
665             return;
666
667         /* The role may change mid-stream, so we reroute */
668         route_source_output(u, so);
669
670         return;
671     } else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
672         pa_sink *sink;
673
674         if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
675             return;
676
677         name = pa_sprintf_malloc("sink:%s", sink->name);
678
679         old = load_or_initialize_entry(u, &entry, name, "sink:");
680
681         pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
682         pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
683
684     } else  if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) {
685         pa_source *source;
686
687         pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
688
689         if (!(source = pa_idxset_get_by_index(c->sources, idx)))
690             return;
691
692         if (source->monitor_of)
693             return;
694
695         name = pa_sprintf_malloc("source:%s", source->name);
696
697         old = load_or_initialize_entry(u, &entry, name, "source:");
698
699         pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
700         pa_strlcpy(entry.icon, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_ICON_NAME)), sizeof(entry.icon));
701     }
702
703     pa_assert(name);
704
705     if (old) {
706
707         if (entries_equal(old, &entry)) {
708             pa_xfree(old);
709             pa_xfree(name);
710
711             return;
712         }
713
714         pa_xfree(old);
715     }
716
717     key.data = name;
718     key.size = strlen(name);
719
720     data.data = &entry;
721     data.size = sizeof(entry);
722
723     pa_log_info("Storing device %s.", name);
724
725     pa_database_set(u->database, &key, &data, TRUE);
726
727     pa_xfree(name);
728
729     trigger_save(u);
730 }
731
732 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
733     char *name;
734     struct entry *e;
735
736     pa_assert(c);
737     pa_assert(new_data);
738     pa_assert(u);
739
740     name = pa_sprintf_malloc("sink:%s", new_data->name);
741
742     if ((e = read_entry(u, name))) {
743         if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
744             pa_log_info("Restoring description for sink %s.", new_data->name);
745             pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
746         }
747
748         pa_xfree(e);
749     }
750
751     pa_xfree(name);
752
753     return PA_HOOK_OK;
754 }
755
756 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
757     char *name;
758     struct entry *e;
759
760     pa_assert(c);
761     pa_assert(new_data);
762     pa_assert(u);
763
764     name = pa_sprintf_malloc("source:%s", new_data->name);
765
766     if ((e = read_entry(u, name))) {
767         if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
768             /* NB, We cannot detect if we are a monitor here... this could mess things up a bit... */
769             pa_log_info("Restoring description for source %s.", new_data->name);
770             pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
771         }
772
773         pa_xfree(e);
774     }
775
776     pa_xfree(name);
777
778     return PA_HOOK_OK;
779 }
780
781 static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
782     pa_assert(c);
783     pa_assert(new_data);
784     pa_assert(u);
785
786     if (!u->do_routing)
787         return PA_HOOK_OK;
788
789     if (new_data->sink)
790         pa_log_debug("Not restoring device for stream, because already set.");
791     else {
792         const char *role;
793         uint32_t role_index;
794
795         if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE)))
796             role_index = get_role_index("");
797         else
798             role_index = get_role_index(role);
799
800         if (PA_INVALID_INDEX != role_index) {
801             uint32_t device_index;
802
803             device_index = u->preferred_sinks[role_index];
804             if (PA_INVALID_INDEX != device_index) {
805                 pa_sink *sink;
806
807                 if ((sink = pa_idxset_get_by_index(u->core->sinks, device_index))) {
808                     new_data->sink = sink;
809                     new_data->save_sink = TRUE;
810                 }
811             }
812         }
813     }
814
815     return PA_HOOK_OK;
816 }
817
818 static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
819     pa_assert(c);
820     pa_assert(new_data);
821     pa_assert(u);
822
823     if (!u->do_routing)
824         return PA_HOOK_OK;
825
826     if (new_data->direct_on_input)
827         return PA_HOOK_OK;
828
829     if (new_data->source)
830         pa_log_debug("Not restoring device for stream, because already set");
831     else {
832         const char *role;
833         uint32_t role_index;
834
835         if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE)))
836             role_index = get_role_index("");
837         else
838             role_index = get_role_index(role);
839
840         if (PA_INVALID_INDEX != role_index) {
841             uint32_t device_index;
842
843             device_index = u->preferred_sources[role_index];
844             if (PA_INVALID_INDEX != device_index) {
845                 pa_source *source;
846
847                 if ((source = pa_idxset_get_by_index(u->core->sources, device_index))) {
848                     new_data->source = source;
849                     new_data->save_source = TRUE;
850                 }
851             }
852         }
853     }
854
855     return PA_HOOK_OK;
856 }
857
858
859 static pa_hook_result_t sink_put_hook_callback(pa_core *c, PA_GCC_UNUSED pa_sink *sink, struct userdata *u) {
860     pa_assert(c);
861     pa_assert(u);
862     pa_assert(u->core == c);
863     pa_assert(u->on_hotplug);
864
865     notify_subscribers(u);
866
867     return route_sink_inputs(u, NULL);
868 }
869
870 static pa_hook_result_t source_put_hook_callback(pa_core *c, PA_GCC_UNUSED pa_source *source, struct userdata *u) {
871     pa_assert(c);
872     pa_assert(u);
873     pa_assert(u->core == c);
874     pa_assert(u->on_hotplug);
875
876     notify_subscribers(u);
877
878     return route_source_outputs(u, NULL);
879 }
880
881 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
882     pa_assert(c);
883     pa_assert(sink);
884     pa_assert(u);
885     pa_assert(u->core == c);
886     pa_assert(u->on_rescue);
887
888     /* There's no point in doing anything if the core is shut down anyway */
889     if (c->state == PA_CORE_SHUTDOWN)
890         return PA_HOOK_OK;
891
892     notify_subscribers(u);
893
894     return route_sink_inputs(u, sink);
895 }
896
897 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
898     pa_assert(c);
899     pa_assert(source);
900     pa_assert(u);
901     pa_assert(u->core == c);
902     pa_assert(u->on_rescue);
903
904     /* There's no point in doing anything if the core is shut down anyway */
905     if (c->state == PA_CORE_SHUTDOWN)
906         return PA_HOOK_OK;
907
908     notify_subscribers(u);
909
910     return route_source_outputs(u, source);
911 }
912
913
914 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
915     pa_sink *sink;
916     pa_source *source;
917     uint32_t idx;
918     char *n;
919
920     pa_assert(u);
921     pa_assert(name);
922     pa_assert(e);
923
924     if ((n = get_name(name, "sink:"))) {
925         for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) {
926             if (!pa_streq(sink->name, n)) {
927                 continue;
928             }
929
930             pa_log_info("Setting description for sink %s.", sink->name);
931             pa_sink_set_description(sink, e->description);
932         }
933         pa_xfree(n);
934     }
935     else if ((n = get_name(name, "source:"))) {
936         for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) {
937             if (!pa_streq(source->name, n)) {
938                 continue;
939             }
940
941             if (source->monitor_of) {
942                 pa_log_warn("Cowardly refusing to set the description for monitor source %s.", source->name);
943                 continue;
944             }
945
946             pa_log_info("Setting description for source %s.", source->name);
947             pa_source_set_description(source, e->description);
948         }
949         pa_xfree(n);
950     }
951 }
952
953
954 #define EXT_VERSION 1
955
956 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
957   struct userdata *u;
958   uint32_t command;
959   pa_tagstruct *reply = NULL;
960
961   pa_assert(p);
962   pa_assert(m);
963   pa_assert(c);
964   pa_assert(t);
965
966   u = m->userdata;
967
968   if (pa_tagstruct_getu32(t, &command) < 0)
969     goto fail;
970
971   reply = pa_tagstruct_new(NULL, 0);
972   pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
973   pa_tagstruct_putu32(reply, tag);
974
975   switch (command) {
976     case SUBCOMMAND_TEST: {
977       if (!pa_tagstruct_eof(t))
978         goto fail;
979
980       pa_tagstruct_putu32(reply, EXT_VERSION);
981       break;
982     }
983
984     case SUBCOMMAND_READ: {
985       pa_datum key;
986       pa_bool_t done;
987
988       if (!pa_tagstruct_eof(t))
989         goto fail;
990
991       done = !pa_database_first(u->database, &key, NULL);
992
993       while (!done) {
994         pa_datum next_key;
995         struct entry *e;
996         char *name;
997
998         done = !pa_database_next(u->database, &key, &next_key, NULL);
999
1000         name = pa_xstrndup(key.data, key.size);
1001         pa_datum_free(&key);
1002
1003         if ((e = read_entry(u, name))) {
1004             uint32_t idx;
1005             char *devname;
1006             pa_bool_t available = FALSE;
1007
1008             if ((devname = get_name(name, "sink:"))) {
1009                 pa_sink* s;
1010                 PA_IDXSET_FOREACH(s, u->core->sinks, idx) {
1011                     if (strcmp(s->name, devname) == 0) {
1012                         available = TRUE;
1013                         break;
1014                     }
1015                 }
1016                 pa_xfree(devname);
1017             } else if ((devname = get_name(name, "source:"))) {
1018                 pa_source* s;
1019                 PA_IDXSET_FOREACH(s, u->core->sources, idx) {
1020                     if (strcmp(s->name, devname) == 0) {
1021                         available = TRUE;
1022                         break;
1023                     }
1024                 }
1025                 pa_xfree(devname);
1026             }
1027
1028             pa_tagstruct_puts(reply, name);
1029             pa_tagstruct_puts(reply, e->description);
1030             pa_tagstruct_puts(reply, e->icon);
1031             pa_tagstruct_put_boolean(reply, available);
1032             pa_tagstruct_putu32(reply, NUM_ROLES);
1033
1034             for (uint32_t i = ROLE_NONE; i < NUM_ROLES; ++i) {
1035                 pa_tagstruct_puts(reply, role_names[i]);
1036                 pa_tagstruct_putu32(reply, e->priority[i]);
1037             }
1038
1039             pa_xfree(e);
1040         }
1041
1042         pa_xfree(name);
1043
1044         key = next_key;
1045       }
1046
1047       break;
1048     }
1049
1050     case SUBCOMMAND_RENAME: {
1051
1052         struct entry *e;
1053         const char *device, *description;
1054
1055         if (pa_tagstruct_gets(t, &device) < 0 ||
1056           pa_tagstruct_gets(t, &description) < 0)
1057           goto fail;
1058
1059         if (!device || !*device || !description || !*description)
1060           goto fail;
1061
1062         if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
1063             pa_datum key, data;
1064
1065             pa_strlcpy(e->description, description, sizeof(e->description));
1066
1067             key.data = (char *) device;
1068             key.size = strlen(device);
1069
1070             data.data = e;
1071             data.size = sizeof(*e);
1072
1073             if (pa_database_set(u->database, &key, &data, TRUE) == 0) {
1074                 apply_entry(u, device, e);
1075
1076                 trigger_save(u);
1077             }
1078             else
1079                 pa_log_warn("Could not save device");
1080
1081             pa_xfree(e);
1082         }
1083         else
1084             pa_log_warn("Could not rename device %s, no entry in database", device);
1085
1086       break;
1087     }
1088
1089     case SUBCOMMAND_DELETE:
1090
1091       while (!pa_tagstruct_eof(t)) {
1092         const char *name;
1093         pa_datum key;
1094
1095         if (pa_tagstruct_gets(t, &name) < 0)
1096           goto fail;
1097
1098         key.data = (char*) name;
1099         key.size = strlen(name);
1100
1101         /** @todo: Reindex the priorities */
1102         pa_database_unset(u->database, &key);
1103       }
1104
1105       trigger_save(u);
1106
1107       break;
1108
1109     case SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING: {
1110
1111         pa_bool_t enable;
1112
1113         if (pa_tagstruct_get_boolean(t, &enable) < 0)
1114             goto fail;
1115
1116         if ((u->do_routing = enable)) {
1117             /* Update our caches */
1118             update_highest_priority_device_indexes(u, "sink:", NULL);
1119             update_highest_priority_device_indexes(u, "source:", NULL);
1120         }
1121
1122         break;
1123     }
1124
1125     case SUBCOMMAND_REORDER: {
1126
1127         const char *role;
1128         struct entry *e;
1129         uint32_t role_index, n_devices;
1130         pa_datum key, data;
1131         pa_bool_t done, sink_mode = TRUE;
1132         struct device_t { uint32_t prio; char *device; };
1133         struct device_t *device;
1134         struct device_t **devices;
1135         uint32_t i, idx, offset;
1136         pa_hashmap *h;
1137         /*void *state;*/
1138         pa_bool_t first;
1139
1140         if (pa_tagstruct_gets(t, &role) < 0 ||
1141             pa_tagstruct_getu32(t, &n_devices) < 0 ||
1142             n_devices < 1)
1143             goto fail;
1144
1145         if (PA_INVALID_INDEX == (role_index = get_role_index(role)))
1146            goto fail;
1147
1148         /* Cycle through the devices given and make sure they exist */
1149         h = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1150         first = TRUE;
1151         idx = 0;
1152         for (i = 0; i < n_devices; ++i) {
1153             const char *s;
1154             if (pa_tagstruct_gets(t, &s) < 0) {
1155                 while ((device = pa_hashmap_steal_first(h))) {
1156                     pa_xfree(device->device);
1157                     pa_xfree(device);
1158                 }
1159
1160                 pa_hashmap_free(h, NULL, NULL);
1161                 pa_log_error("Protocol error on reorder");
1162                 goto fail;
1163             }
1164
1165             /* Ensure this is a valid entry */
1166             if (!(e = read_entry(u, s))) {
1167                 while ((device = pa_hashmap_steal_first(h))) {
1168                     pa_xfree(device->device);
1169                     pa_xfree(device);
1170                 }
1171
1172                 pa_hashmap_free(h, NULL, NULL);
1173                 pa_log_error("Client specified an unknown device in it's reorder list.");
1174                 goto fail;
1175             }
1176             pa_xfree(e);
1177
1178             if (first) {
1179                 first = FALSE;
1180                 sink_mode = (0 == strncmp("sink:", s, 5));
1181             } else if ((sink_mode && 0 != strncmp("sink:", s, 5))
1182                        || (!sink_mode && 0 != strncmp("source:", s, 7)))
1183             {
1184                 while ((device = pa_hashmap_steal_first(h))) {
1185                     pa_xfree(device->device);
1186                     pa_xfree(device);
1187                 }
1188
1189                 pa_hashmap_free(h, NULL, NULL);
1190                 pa_log_error("Attempted to reorder mixed devices (sinks and sources)");
1191                 goto fail;
1192             }
1193
1194             /* Add the device to our hashmap. If it's alredy in it, free it now and carry on */
1195             device = pa_xnew(struct device_t, 1);
1196             device->device = pa_xstrdup(s);
1197             if (pa_hashmap_put(h, device->device, device) == 0) {
1198                 device->prio = idx;
1199                 idx++;
1200             } else {
1201                 pa_xfree(device->device);
1202                 pa_xfree(device);
1203             }
1204         }
1205
1206         /*pa_log_debug("Hashmap contents (received from client)");
1207         PA_HASHMAP_FOREACH(device, h, state) {
1208             pa_log_debug("  - %s (%d)", device->device, device->prio);
1209         }*/
1210
1211         /* Now cycle through our list and add all the devices.
1212            This has the effect of addign in any in our DB,
1213            not specified in the device list (and thus will be
1214            tacked on at the end) */
1215         offset = idx;
1216         done = !pa_database_first(u->database, &key, NULL);
1217
1218         while (!done && idx < 256) {
1219             pa_datum next_key;
1220
1221             done = !pa_database_next(u->database, &key, &next_key, NULL);
1222
1223             device = pa_xnew(struct device_t, 1);
1224             device->device = pa_xstrndup(key.data, key.size);
1225             if ((sink_mode && 0 == strncmp("sink:", device->device, 5))
1226                 || (!sink_mode && 0 == strncmp("source:", device->device, 7))) {
1227
1228                 /* Add the device to our hashmap. If it's alredy in it, free it now and carry on */
1229                 if (pa_hashmap_put(h, device->device, device) == 0
1230                     && (e = read_entry(u, device->device)) && ENTRY_VERSION == e->version) {
1231                     /* We add offset on to the existing priorirty so that when we order, the
1232                        existing entries are always lower priority than the new ones. */
1233                     device->prio = (offset + e->priority[role_index]);
1234                     pa_xfree(e);
1235                 }
1236                 else {
1237                     pa_xfree(device->device);
1238                     pa_xfree(device);
1239                 }
1240             } else {
1241                 pa_xfree(device->device);
1242                 pa_xfree(device);
1243             }
1244
1245             pa_datum_free(&key);
1246
1247             key = next_key;
1248         }
1249
1250         /*pa_log_debug("Hashmap contents (combined with database)");
1251         PA_HASHMAP_FOREACH(device, h, state) {
1252             pa_log_debug("  - %s (%d)", device->device, device->prio);
1253         }*/
1254
1255         /* Now we put all the entries in a simple list for sorting it. */
1256         n_devices = pa_hashmap_size(h);
1257         devices = pa_xnew(struct device_t *,  n_devices);
1258         idx = 0;
1259         while ((device = pa_hashmap_steal_first(h))) {
1260             devices[idx++] = device;
1261         }
1262         pa_hashmap_free(h, NULL, NULL);
1263
1264         /* Simple bubble sort */
1265         for (i = 0; i < n_devices; ++i) {
1266             for (uint32_t j = i; j < n_devices; ++j) {
1267                 if (devices[i]->prio > devices[j]->prio) {
1268                     struct device_t *tmp;
1269                     tmp = devices[i];
1270                     devices[i] = devices[j];
1271                     devices[j] = tmp;
1272                 }
1273             }
1274         }
1275
1276         /*pa_log_debug("Sorted device list");
1277         for (i = 0; i < n_devices; ++i) {
1278             pa_log_debug("  - %s (%d)", devices[i]->device, devices[i]->prio);
1279         }*/
1280
1281         /* Go through in order and write the new entry and cleanup our own list */
1282         idx = 1;
1283         first = TRUE;
1284         for (i = 0; i < n_devices; ++i) {
1285             if ((e = read_entry(u, devices[i]->device)) && ENTRY_VERSION == e->version) {
1286                 if (e->priority[role_index] == idx)
1287                     idx++;
1288                 else {
1289                     e->priority[role_index] = idx;
1290
1291                     key.data = (char *) devices[i]->device;
1292                     key.size = strlen(devices[i]->device);
1293
1294                     data.data = e;
1295                     data.size = sizeof(*e);
1296
1297                     if (pa_database_set(u->database, &key, &data, TRUE) == 0) {
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             if (sink_mode)
1313                 route_sink_inputs(u, NULL);
1314             else
1315                 route_source_outputs(u, NULL);
1316         }
1317
1318         break;
1319     }
1320
1321     case SUBCOMMAND_SUBSCRIBE: {
1322
1323       pa_bool_t enabled;
1324
1325       if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1326         !pa_tagstruct_eof(t))
1327         goto fail;
1328
1329       if (enabled)
1330         pa_idxset_put(u->subscribed, c, NULL);
1331       else
1332         pa_idxset_remove_by_data(u->subscribed, c, NULL);
1333
1334       break;
1335     }
1336
1337     default:
1338       goto fail;
1339   }
1340
1341   pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1342   return 0;
1343
1344   fail:
1345
1346   if (reply)
1347     pa_tagstruct_free(reply);
1348
1349   return -1;
1350 }
1351
1352 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
1353     pa_assert(p);
1354     pa_assert(c);
1355     pa_assert(u);
1356
1357     pa_idxset_remove_by_data(u->subscribed, c, NULL);
1358     return PA_HOOK_OK;
1359 }
1360
1361 int pa__init(pa_module*m) {
1362     pa_modargs *ma = NULL;
1363     struct userdata *u;
1364     char *fname;
1365     pa_sink *sink;
1366     pa_source *source;
1367     uint32_t idx;
1368     pa_bool_t do_routing = FALSE, on_hotplug = TRUE, on_rescue = TRUE;
1369
1370     pa_assert(m);
1371
1372     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1373         pa_log("Failed to parse module arguments");
1374         goto fail;
1375     }
1376
1377     if (pa_modargs_get_value_boolean(ma, "do_routing", &do_routing) < 0 ||
1378         pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
1379         pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
1380         pa_log("on_hotplug= and on_rescue= expect boolean arguments");
1381         goto fail;
1382     }
1383
1384     m->userdata = u = pa_xnew0(struct userdata, 1);
1385     u->core = m->core;
1386     u->module = m;
1387     u->do_routing = do_routing;
1388     u->on_hotplug = on_hotplug;
1389     u->on_rescue = on_rescue;
1390     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1391
1392     u->protocol = pa_native_protocol_get(m->core);
1393     pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1394
1395     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);
1396
1397     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);
1398
1399     /* Used to handle device description management */
1400     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);
1401     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);
1402
1403     /* The following slots are used to deal with routing */
1404     /* A little bit later than module-stream-restore, module-intended-roles */
1405     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);
1406     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);
1407
1408     if (on_hotplug) {
1409         /* A little bit later than module-stream-restore, module-intended-roles */
1410         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);
1411         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);
1412     }
1413
1414     if (on_rescue) {
1415         /* A little bit later than module-stream-restore, module-intended-roles, a little bit earlier than module-rescue-streams, ... */
1416         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);
1417         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);
1418     }
1419
1420     if (!(fname = pa_state_path("device-manager", TRUE)))
1421         goto fail;
1422
1423     if (!(u->database = pa_database_open(fname, TRUE))) {
1424         pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
1425         pa_xfree(fname);
1426         goto fail;
1427     }
1428
1429     pa_log_info("Sucessfully opened database file '%s'.", fname);
1430     pa_xfree(fname);
1431
1432     /* We cycle over all the available sinks so that they are added to our database if they are not in it yet */
1433     PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
1434         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
1435
1436     PA_IDXSET_FOREACH(source, m->core->sources, idx)
1437         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
1438
1439     /* Perform the routing (if it's enabled) which will update our priority list cache too */
1440     for (uint32_t i = 0; i < NUM_ROLES; ++i) {
1441         u->preferred_sinks[i] = u->preferred_sources[i] = PA_INVALID_INDEX;
1442     }
1443
1444     route_sink_inputs(u, NULL);
1445     route_source_outputs(u, NULL);
1446
1447 #ifdef DUMP_DATABASE
1448     dump_database(u);
1449 #endif
1450
1451     pa_modargs_free(ma);
1452     return 0;
1453
1454 fail:
1455     pa__done(m);
1456
1457     if (ma)
1458         pa_modargs_free(ma);
1459
1460     return  -1;
1461 }
1462
1463 void pa__done(pa_module*m) {
1464     struct userdata* u;
1465
1466     pa_assert(m);
1467
1468     if (!(u = m->userdata))
1469         return;
1470
1471     if (u->subscription)
1472         pa_subscription_free(u->subscription);
1473
1474     if (u->sink_new_hook_slot)
1475         pa_hook_slot_free(u->sink_new_hook_slot);
1476     if (u->source_new_hook_slot)
1477         pa_hook_slot_free(u->source_new_hook_slot);
1478
1479     if (u->sink_input_new_hook_slot)
1480         pa_hook_slot_free(u->sink_input_new_hook_slot);
1481     if (u->source_output_new_hook_slot)
1482         pa_hook_slot_free(u->source_output_new_hook_slot);
1483
1484     if (u->sink_put_hook_slot)
1485         pa_hook_slot_free(u->sink_put_hook_slot);
1486     if (u->source_put_hook_slot)
1487         pa_hook_slot_free(u->source_put_hook_slot);
1488
1489     if (u->sink_unlink_hook_slot)
1490         pa_hook_slot_free(u->sink_unlink_hook_slot);
1491     if (u->source_unlink_hook_slot)
1492         pa_hook_slot_free(u->source_unlink_hook_slot);
1493
1494     if (u->save_time_event)
1495         u->core->mainloop->time_free(u->save_time_event);
1496
1497     if (u->database)
1498         pa_database_close(u->database);
1499
1500     if (u->protocol) {
1501         pa_native_protocol_remove_ext(u->protocol, m);
1502         pa_native_protocol_unref(u->protocol);
1503     }
1504
1505     if (u->subscribed)
1506         pa_idxset_free(u->subscribed, NULL, NULL);
1507
1508     pa_xfree(u);
1509 }