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