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