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