device-manager: Some efficiency and safety tweaks
[profile/ivi/pulseaudio.git] / src / modules / module-device-manager.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2006-2008 Lennart Poettering
5   Copyright 2009 Colin Guthrie
6
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/util.h>
39 #include <pulse/rtclock.h>
40
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/modargs.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/core-subscribe.h>
47 #include <pulsecore/sink-input.h>
48 #include <pulsecore/source-output.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/protocol-native.h>
51 #include <pulsecore/pstream.h>
52 #include <pulsecore/pstream-util.h>
53 #include <pulsecore/database.h>
54
55 #include "module-device-manager-symdef.h"
56
57 PA_MODULE_AUTHOR("Colin Guthrie");
58 PA_MODULE_DESCRIPTION("Keep track of devices (and their descriptions) both past and present");
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
68 static const char* const valid_modargs[] = {
69     "do_routing",
70     "on_hotplug",
71     "on_rescue",
72     NULL
73 };
74
75 struct userdata {
76     pa_core *core;
77     pa_module *module;
78     pa_subscription *subscription;
79     pa_hook_slot
80         *sink_new_hook_slot,
81         *source_new_hook_slot,
82         *sink_input_new_hook_slot,
83         *source_output_new_hook_slot,
84         *sink_put_hook_slot,
85         *source_put_hook_slot,
86         *sink_unlink_hook_slot,
87         *source_unlink_hook_slot,
88         *connection_unlink_hook_slot;
89     pa_time_event *save_time_event;
90     pa_database *database;
91
92     pa_native_protocol *protocol;
93     pa_idxset *subscribed;
94
95     pa_bool_t on_hotplug;
96     pa_bool_t on_rescue;
97     pa_bool_t do_routing;
98 };
99
100 #define ENTRY_VERSION 1
101
102 #define NUM_ROLES 9
103 enum {
104     ROLE_NONE,
105     ROLE_VIDEO,
106     ROLE_MUSIC,
107     ROLE_GAME,
108     ROLE_EVENT,
109     ROLE_PHONE,
110     ROLE_ANIMATION,
111     ROLE_PRODUCTION,
112     ROLE_A11Y,
113 };
114
115 typedef uint32_t role_indexes_t[NUM_ROLES];
116
117 struct entry {
118     uint8_t version;
119     char description[PA_NAME_MAX];
120     role_indexes_t priority;
121 } PA_GCC_PACKED;
122
123 enum {
124     SUBCOMMAND_TEST,
125     SUBCOMMAND_READ,
126     SUBCOMMAND_RENAME,
127     SUBCOMMAND_DELETE,
128     SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
129     SUBCOMMAND_PREFER_DEVICE,
130     SUBCOMMAND_DEFER_DEVICE,
131     SUBCOMMAND_SUBSCRIBE,
132     SUBCOMMAND_EVENT
133 };
134
135 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
136     struct userdata *u = userdata;
137
138     pa_assert(a);
139     pa_assert(e);
140     pa_assert(u);
141
142     pa_assert(e == u->save_time_event);
143     u->core->mainloop->time_free(u->save_time_event);
144     u->save_time_event = NULL;
145
146     pa_database_sync(u->database);
147     pa_log_info("Synced.");
148 }
149
150 static struct entry* read_entry(struct userdata *u, const char *name) {
151     pa_datum key, data;
152     struct entry *e;
153
154     pa_assert(u);
155     pa_assert(name);
156
157     key.data = (char*) name;
158     key.size = strlen(name);
159
160     pa_zero(data);
161
162     if (!pa_database_get(u->database, &key, &data))
163         goto fail;
164
165     if (data.size != sizeof(struct entry)) {
166         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));
167         goto fail;
168     }
169
170     e = (struct entry*) data.data;
171
172     if (e->version != ENTRY_VERSION) {
173         pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name);
174         goto fail;
175     }
176
177     if (!memchr(e->description, 0, sizeof(e->description))) {
178         pa_log_warn("Database contains entry for device %s with missing NUL byte in description", name);
179         goto fail;
180     }
181
182     return e;
183
184 fail:
185
186     pa_datum_free(&data);
187     return NULL;
188 }
189
190 static void trigger_save(struct userdata *u) {
191     pa_native_connection *c;
192     uint32_t idx;
193
194     for (c = pa_idxset_first(u->subscribed, &idx); c; c = pa_idxset_next(u->subscribed, &idx)) {
195         pa_tagstruct *t;
196
197         t = pa_tagstruct_new(NULL, 0);
198         pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
199         pa_tagstruct_putu32(t, 0);
200         pa_tagstruct_putu32(t, u->module->index);
201         pa_tagstruct_puts(t, u->module->name);
202         pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
203
204         pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
205     }
206
207     if (u->save_time_event)
208         return;
209
210     u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
211 }
212
213 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
214     if (strncmp(a->description, b->description, sizeof(a->description)))
215         return FALSE;
216
217     return TRUE;
218 }
219
220 static inline struct entry *load_or_initialize_entry(struct userdata *u, struct entry *entry, const char *name, const char *prefix) {
221     struct entry *old;
222
223     pa_assert(u);
224     pa_assert(entry);
225     pa_assert(name);
226     pa_assert(prefix);
227
228     if ((old = read_entry(u, name)))
229         *entry = *old;
230     else {
231         /* This is a new device, so make sure we write it's priority list correctly */
232         role_indexes_t max_priority;
233         pa_datum key;
234         pa_bool_t done;
235
236         pa_zero(max_priority);
237         done = !pa_database_first(u->database, &key, NULL);
238
239         /* Find all existing devices with the same prefix so we calculate the current max priority for each role */
240         while (!done) {
241             pa_datum next_key;
242
243             done = !pa_database_next(u->database, &key, &next_key, NULL);
244
245             if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
246                 char *name2;
247                 struct entry *e;
248
249                 name2 = pa_xstrndup(key.data, key.size);
250
251                 if ((e = read_entry(u, name2))) {
252                     for (uint32_t i = 0; i < NUM_ROLES; ++i) {
253                         max_priority[i] = PA_MAX(max_priority[i], e->priority[i]);
254                     }
255
256                     pa_xfree(e);
257                 }
258
259                 pa_xfree(name2);
260             }
261             pa_datum_free(&key);
262             key = next_key;
263         }
264
265         /* Actually initialise our entry now we've calculated it */
266         for (uint32_t i = 0; i < NUM_ROLES; ++i) {
267             entry->priority[i] = max_priority[i] + 1;
268         }
269     }
270
271     return old;
272 }
273
274 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
275     struct userdata *u = userdata;
276     struct entry entry, *old = NULL;
277     char *name = NULL;
278     pa_datum key, data;
279
280     pa_assert(c);
281     pa_assert(u);
282
283     if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
284         t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
285         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
286         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
287         return;
288
289     pa_zero(entry);
290     entry.version = ENTRY_VERSION;
291
292     if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
293         pa_sink *sink;
294
295         if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
296             return;
297
298         name = pa_sprintf_malloc("sink:%s", sink->name);
299
300         old = load_or_initialize_entry(u, &entry, name, "sink:");
301
302         pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
303
304     } else {
305         pa_source *source;
306
307         pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
308
309         if (!(source = pa_idxset_get_by_index(c->sources, idx)))
310             return;
311
312         if (source->monitor_of)
313             return;
314
315         name = pa_sprintf_malloc("source:%s", source->name);
316
317         old = load_or_initialize_entry(u, &entry, name, "source:");
318
319         pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
320     }
321
322     if (old) {
323
324         if (entries_equal(old, &entry)) {
325             pa_xfree(old);
326             pa_xfree(name);
327             return;
328         }
329
330         pa_xfree(old);
331     }
332
333     key.data = name;
334     key.size = strlen(name);
335
336     data.data = &entry;
337     data.size = sizeof(entry);
338
339     pa_log_info("Storing device %s.", name);
340
341     pa_database_set(u->database, &key, &data, TRUE);
342
343     pa_xfree(name);
344
345     trigger_save(u);
346 }
347
348 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
349     char *name;
350     struct entry *e;
351
352     pa_assert(c);
353     pa_assert(new_data);
354     pa_assert(u);
355
356     name = pa_sprintf_malloc("sink:%s", new_data->name);
357
358     if ((e = read_entry(u, name))) {
359         if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
360             pa_log_info("Restoring description for sink %s.", new_data->name);
361             pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
362         }
363
364         pa_xfree(e);
365     }
366
367     pa_xfree(name);
368
369     return PA_HOOK_OK;
370 }
371
372 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
373     char *name;
374     struct entry *e;
375
376     pa_assert(c);
377     pa_assert(new_data);
378     pa_assert(u);
379
380     name = pa_sprintf_malloc("source:%s", new_data->name);
381
382     if ((e = read_entry(u, name))) {
383         if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
384             /* NB, We cannot detect if we are a monitor here... this could mess things up a bit... */
385             pa_log_info("Restoring description for source %s.", new_data->name);
386             pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
387         }
388
389         pa_xfree(e);
390     }
391
392     pa_xfree(name);
393
394     return PA_HOOK_OK;
395 }
396
397 static char *get_name(const char *key, const char *prefix) {
398     char *t;
399
400     if (strncmp(key, prefix, strlen(prefix)))
401         return NULL;
402
403     t = pa_xstrdup(key + strlen(prefix));
404     return t;
405 }
406
407 static uint32_t get_role_index(const char* role) {
408     pa_assert(role);
409
410     if (strcmp(role, "") == 0)
411         return ROLE_NONE;
412     if (strcmp(role, "video") == 0)
413         return ROLE_VIDEO;
414     if (strcmp(role, "music") == 0)
415         return ROLE_MUSIC;
416     if (strcmp(role, "game") == 0)
417         return ROLE_GAME;
418     if (strcmp(role, "event") == 0)
419         return ROLE_EVENT;
420     if (strcmp(role, "phone") == 0)
421         return ROLE_PHONE;
422     if (strcmp(role, "animation") == 0)
423         return ROLE_ANIMATION;
424     if (strcmp(role, "production") == 0)
425         return ROLE_PRODUCTION;
426     if (strcmp(role, "a11y") == 0)
427         return ROLE_A11Y;
428     return PA_INVALID_INDEX;
429 }
430
431 static role_indexes_t *get_highest_priority_device_indexes(struct userdata *u, const char *prefix) {
432     role_indexes_t *indexes, highest_priority_available;
433     pa_datum key;
434     pa_bool_t done, sink_mode;
435
436     pa_assert(u);
437     pa_assert(prefix);
438
439     indexes = pa_xnew(role_indexes_t, 1);
440     for (uint32_t i = 0; i < NUM_ROLES; ++i) {
441         *indexes[i] = PA_INVALID_INDEX;
442     }
443     pa_zero(highest_priority_available);
444
445     sink_mode = (strcmp(prefix, "sink:") == 0);
446
447     done = !pa_database_first(u->database, &key, NULL);
448
449     /* Find all existing devices with the same prefix so we find the highest priority device for each role */
450     while (!done) {
451         pa_datum next_key;
452
453         done = !pa_database_next(u->database, &key, &next_key, NULL);
454
455         if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
456             char *name;
457             struct entry *e;
458
459             name = pa_xstrndup(key.data, key.size);
460
461             if ((e = read_entry(u, name))) {
462                 for (uint32_t i = 0; i < NUM_ROLES; ++i) {
463                     if (highest_priority_available[i] && e->priority[i] < highest_priority_available[i]) {
464                         /* We've found a device with a higher priority than that we've currently got,
465                            so see if it is currently available or not and update our list */
466                         uint32_t idx;
467                         pa_bool_t found = FALSE;
468                         char *device_name = get_name(name, prefix);
469
470                         if (sink_mode) {
471                             pa_sink *sink;
472
473                             PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
474                                 if (strcmp(sink->name, device_name) == 0) {
475                                     found = TRUE;
476                                     idx = sink->index; /* Is this needed? */
477                                     break;
478                                 }
479                             }
480                         } else {
481                             pa_source *source;
482
483                             PA_IDXSET_FOREACH(source, u->core->sources, idx) {
484                                 if (strcmp(source->name, device_name) == 0) {
485                                     found = TRUE;
486                                     idx = source->index; /* Is this needed? */
487                                     break;
488                                 }
489                             }
490                         }
491                         if (found) {
492                             highest_priority_available[i] = e->priority[i];
493                             *indexes[i] = idx;
494                         }
495
496                         pa_xfree(device_name);
497                     }
498                 }
499
500                 pa_xfree(e);
501             }
502
503             pa_xfree(name);
504         }
505
506         pa_datum_free(&key);
507         key = next_key;
508     }
509
510     return indexes;
511 }
512
513
514 static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
515     pa_assert(c);
516     pa_assert(new_data);
517     pa_assert(u);
518
519     if (!u->do_routing)
520         return PA_HOOK_OK;
521
522     if (new_data->sink)
523         pa_log_debug("Not restoring device for stream, because already set.");
524     else {
525         const char *role;
526         uint32_t role_index;
527
528         if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE)))
529             role_index = get_role_index("");
530         else
531             role_index = get_role_index(role);
532
533         if (PA_INVALID_INDEX != role_index) {
534             role_indexes_t *indexes;
535             uint32_t device_index;
536
537             pa_assert_se(indexes = get_highest_priority_device_indexes(u, "sink:"));
538
539             device_index = *indexes[role_index];
540             if (PA_INVALID_INDEX != device_index) {
541                 pa_sink *sink;
542
543                 if ((sink = pa_idxset_get_by_index(u->core->sinks, device_index))) {
544                     new_data->sink = sink;
545                     new_data->save_sink = TRUE;
546                 }
547             }
548         }
549     }
550
551     return PA_HOOK_OK;
552 }
553
554 static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
555     pa_assert(c);
556     pa_assert(new_data);
557     pa_assert(u);
558
559     if (!u->do_routing)
560         return PA_HOOK_OK;
561
562     if (new_data->direct_on_input)
563         return PA_HOOK_OK;
564
565     if (new_data->source)
566         pa_log_debug("Not restoring device for stream, because already set");
567     else {
568         const char *role;
569         uint32_t role_index;
570
571         if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE)))
572             role_index = get_role_index("");
573         else
574             role_index = get_role_index(role);
575
576         if (PA_INVALID_INDEX != role_index) {
577             role_indexes_t *indexes;
578             uint32_t device_index;
579
580             pa_assert_se(indexes = get_highest_priority_device_indexes(u, "source:"));
581
582             device_index = *indexes[role_index];
583             if (PA_INVALID_INDEX != device_index) {
584                 pa_source *source;
585
586                 if ((source = pa_idxset_get_by_index(u->core->sources, device_index))) {
587                     new_data->source = source;
588                     new_data->save_source = TRUE;
589                 }
590             }
591         }
592     }
593
594     return PA_HOOK_OK;
595 }
596
597 static pa_hook_result_t reroute_sinks(struct userdata *u) {
598     pa_sink_input *si;
599     role_indexes_t *indexes;
600     uint32_t idx;
601
602     pa_assert(u);
603
604     if (!u->do_routing)
605         return PA_HOOK_OK;
606
607     pa_assert_se(indexes = get_highest_priority_device_indexes(u, "sink:"));
608
609     PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
610         const char *role;
611         uint32_t role_index, device_index;
612         pa_sink *sink;
613
614         if (si->save_sink)
615             continue;
616
617         /* Skip this if it is already in the process of being moved anyway */
618         if (!si->sink)
619             continue;
620
621         /* It might happen that a stream and a sink are set up at the
622         same time, in which case we want to make sure we don't
623         interfere with that */
624         if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
625             continue;
626
627         if (!(role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE)))
628             role_index = get_role_index("");
629         else
630             role_index = get_role_index(role);
631
632         if (PA_INVALID_INDEX == role_index)
633             continue;
634
635         device_index = *indexes[role_index];
636         if (PA_INVALID_INDEX == device_index)
637             continue;
638
639         if (!(sink = pa_idxset_get_by_index(u->core->sinks, device_index)))
640             continue;
641
642         if (si->sink != sink)
643             pa_sink_input_move_to(si, sink, TRUE);
644     }
645
646     pa_xfree(indexes);
647
648     return PA_HOOK_OK;
649 }
650
651 static pa_hook_result_t reroute_sources(struct userdata *u) {
652     pa_source_output *so;
653     role_indexes_t *indexes;
654     uint32_t idx;
655
656     pa_assert(u);
657
658     if (!u->do_routing)
659         return PA_HOOK_OK;
660
661     pa_assert_se(indexes = get_highest_priority_device_indexes(u, "source:"));
662
663     PA_IDXSET_FOREACH(so, u->core->source_outputs, idx) {
664         const char *role;
665         uint32_t role_index, device_index;
666         pa_source *source;
667
668         if (so->save_source)
669             continue;
670
671         if (so->direct_on_input)
672             continue;
673
674         /* Skip this if it is already in the process of being moved anyway */
675         if (!so->source)
676             continue;
677
678         /* It might happen that a stream and a source are set up at the
679         same time, in which case we want to make sure we don't
680         interfere with that */
681         if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
682             continue;
683
684         if (!(role = pa_proplist_gets(so->proplist, PA_PROP_MEDIA_ROLE)))
685             role_index = get_role_index("");
686         else
687             role_index = get_role_index(role);
688
689         if (PA_INVALID_INDEX == role_index)
690             continue;
691
692         device_index = *indexes[role_index];
693         if (PA_INVALID_INDEX == device_index)
694             continue;
695
696         if (!(source = pa_idxset_get_by_index(u->core->sources, device_index)))
697             continue;
698
699         if (so->source != source)
700             pa_source_output_move_to(so, source, TRUE);
701     }
702
703     pa_xfree(indexes);
704
705     return PA_HOOK_OK;
706 }
707
708 static pa_hook_result_t sink_put_hook_callback(pa_core *c, PA_GCC_UNUSED pa_sink *sink, struct userdata *u) {
709     pa_assert(c);
710     pa_assert(u);
711     pa_assert(u->core == c);
712     pa_assert(u->on_hotplug);
713
714     return reroute_sinks(u);
715 }
716
717 static pa_hook_result_t source_put_hook_callback(pa_core *c, PA_GCC_UNUSED pa_source *source, struct userdata *u) {
718     pa_assert(c);
719     pa_assert(u);
720     pa_assert(u->core == c);
721     pa_assert(u->on_hotplug);
722
723     return reroute_sources(u);
724 }
725
726 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, PA_GCC_UNUSED pa_sink *sink, struct userdata *u) {
727     pa_assert(c);
728     pa_assert(u);
729     pa_assert(u->core == c);
730     pa_assert(u->on_rescue);
731
732     /* There's no point in doing anything if the core is shut down anyway */
733     if (c->state == PA_CORE_SHUTDOWN)
734         return PA_HOOK_OK;
735
736     return reroute_sinks(u);
737 }
738
739 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, PA_GCC_UNUSED pa_source *source, struct userdata *u) {
740     pa_assert(c);
741     pa_assert(u);
742     pa_assert(u->core == c);
743     pa_assert(u->on_rescue);
744
745     /* There's no point in doing anything if the core is shut down anyway */
746     if (c->state == PA_CORE_SHUTDOWN)
747         return PA_HOOK_OK;
748
749     return reroute_sinks(u);
750 }
751
752
753 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
754     pa_sink *sink;
755     pa_source *source;
756     uint32_t idx;
757     char *n;
758
759     pa_assert(u);
760     pa_assert(name);
761     pa_assert(e);
762
763     if ((n = get_name(name, "sink:"))) {
764         for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) {
765             if (!pa_streq(sink->name, n)) {
766                 continue;
767             }
768
769             pa_log_info("Setting description for sink %s.", sink->name);
770             pa_sink_set_description(sink, e->description);
771         }
772         pa_xfree(n);
773     }
774     else if ((n = get_name(name, "source:"))) {
775         for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) {
776             if (!pa_streq(source->name, n)) {
777                 continue;
778             }
779
780             if (source->monitor_of) {
781                 pa_log_warn("Cowardly refusing to set the description for monitor source %s.", source->name);
782                 continue;
783             }
784
785             pa_log_info("Setting description for source %s.", source->name);
786             pa_source_set_description(source, e->description);
787         }
788         pa_xfree(n);
789     }
790 }
791
792
793 #define EXT_VERSION 1
794
795 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
796   struct userdata *u;
797   uint32_t command;
798   pa_tagstruct *reply = NULL;
799
800   pa_assert(p);
801   pa_assert(m);
802   pa_assert(c);
803   pa_assert(t);
804
805   u = m->userdata;
806
807   if (pa_tagstruct_getu32(t, &command) < 0)
808     goto fail;
809
810   reply = pa_tagstruct_new(NULL, 0);
811   pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
812   pa_tagstruct_putu32(reply, tag);
813
814   switch (command) {
815     case SUBCOMMAND_TEST: {
816       if (!pa_tagstruct_eof(t))
817         goto fail;
818
819       pa_tagstruct_putu32(reply, EXT_VERSION);
820       break;
821     }
822
823     case SUBCOMMAND_READ: {
824       pa_datum key;
825       pa_bool_t done;
826
827       if (!pa_tagstruct_eof(t))
828         goto fail;
829
830       done = !pa_database_first(u->database, &key, NULL);
831
832       while (!done) {
833         pa_datum next_key;
834         struct entry *e;
835         char *name;
836
837         done = !pa_database_next(u->database, &key, &next_key, NULL);
838
839         name = pa_xstrndup(key.data, key.size);
840         pa_datum_free(&key);
841
842         if ((e = read_entry(u, name))) {
843           pa_tagstruct_puts(reply, name);
844           pa_tagstruct_puts(reply, e->description);
845
846           pa_xfree(e);
847         }
848
849         pa_xfree(name);
850
851         key = next_key;
852       }
853
854       break;
855     }
856
857     case SUBCOMMAND_RENAME: {
858
859         struct entry *e;
860         const char *device, *description;
861
862         if (pa_tagstruct_gets(t, &device) < 0 ||
863           pa_tagstruct_gets(t, &description) < 0)
864           goto fail;
865
866         if (!device || !*device || !description || !*description)
867           goto fail;
868
869         if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
870             pa_datum key, data;
871
872             pa_strlcpy(e->description, description, sizeof(e->description));
873
874             key.data = (char *) device;
875             key.size = strlen(device);
876
877             data.data = e;
878             data.size = sizeof(*e);
879
880             if (pa_database_set(u->database, &key, &data, FALSE) == 0) {
881                 apply_entry(u, device, e);
882
883                 trigger_save(u);
884             }
885             else
886                 pa_log_warn("Could not save device");
887
888             pa_xfree(e);
889         }
890         else
891             pa_log_warn("Could not rename device %s, no entry in database", device);
892
893       break;
894     }
895
896     case SUBCOMMAND_DELETE:
897
898       while (!pa_tagstruct_eof(t)) {
899         const char *name;
900         pa_datum key;
901
902         if (pa_tagstruct_gets(t, &name) < 0)
903           goto fail;
904
905         key.data = (char*) name;
906         key.size = strlen(name);
907
908         /** @todo: Reindex the priorities */
909         pa_database_unset(u->database, &key);
910       }
911
912       trigger_save(u);
913
914       break;
915
916     case SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING: {
917
918         pa_bool_t enable;
919
920         if (pa_tagstruct_get_boolean(t, &enable) < 0)
921             goto fail;
922
923         u->do_routing = enable;
924
925         break;
926     }
927
928     case SUBCOMMAND_PREFER_DEVICE:
929     case SUBCOMMAND_DEFER_DEVICE: {
930
931         const char *role, *device;
932         struct entry *e;
933         uint32_t role_index;
934
935         if (pa_tagstruct_gets(t, &role) < 0 ||
936             pa_tagstruct_gets(t, &device) < 0)
937             goto fail;
938
939         if (!role || !device || !*device)
940             goto fail;
941
942         role_index = get_role_index(role);
943         if (PA_INVALID_INDEX == role_index)
944             goto fail;
945
946         if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
947             pa_datum key, data;
948             pa_bool_t done;
949             char* prefix = NULL;
950             uint32_t priority;
951             pa_bool_t haschanged = FALSE;
952
953             if (strncmp(device, "sink:", 5) == 0)
954                 prefix = pa_xstrdup("sink:");
955             else if (strncmp(device, "source:", 7) == 0)
956                 prefix = pa_xstrdup("source:");
957
958             if (!prefix)
959                 goto fail;
960
961             priority = e->priority[role_index];
962
963             /* Now we need to load up all the other entries of this type and shuffle the priroities around */
964
965             done = !pa_database_first(u->database, &key, NULL);
966
967             while (!done && !haschanged) {
968                 pa_datum next_key;
969
970                 done = !pa_database_next(u->database, &key, &next_key, NULL);
971
972                 /* Only read devices with the right prefix */
973                 if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
974                     char *name;
975                     struct entry *e2;
976
977                     name = pa_xstrndup(key.data, key.size);
978
979                     if ((e2 = read_entry(u, name))) {
980                         if (SUBCOMMAND_PREFER_DEVICE == command) {
981                             /* PREFER */
982                             if (e2->priority[role_index] == (priority - 1)) {
983                                 e2->priority[role_index]++;
984                                 haschanged = TRUE;
985                             }
986                         } else {
987                             /* DEFER */
988                             if (e2->priority[role_index] == (priority + 1)) {
989                                 e2->priority[role_index]--;
990                                 haschanged = TRUE;
991                             }
992                         }
993
994                         if (haschanged) {
995                             data.data = e2;
996                             data.size = sizeof(*e2);
997
998                             if (pa_database_set(u->database, &key, &data, FALSE))
999                                 pa_log_warn("Could not save device");
1000                         }
1001
1002                         pa_xfree(e2);
1003                     }
1004
1005                     pa_xfree(name);
1006                 }
1007
1008                 pa_datum_free(&key);
1009                 key = next_key;
1010             }
1011
1012             /* Now write out our actual entry */
1013             if (haschanged) {
1014                 if (SUBCOMMAND_PREFER_DEVICE == command)
1015                     e->priority[role_index]--;
1016                 else
1017                     e->priority[role_index]++;
1018
1019                 key.data = (char *) device;
1020                 key.size = strlen(device);
1021
1022                 data.data = e;
1023                 data.size = sizeof(*e);
1024
1025                 if (pa_database_set(u->database, &key, &data, FALSE))
1026                     pa_log_warn("Could not save device");
1027
1028                 trigger_save(u);
1029             }
1030
1031             pa_xfree(e);
1032
1033             pa_xfree(prefix);
1034         }
1035         else
1036             pa_log_warn("Could not reorder device %s, no entry in database", device);
1037
1038         break;
1039     }
1040
1041     case SUBCOMMAND_SUBSCRIBE: {
1042
1043       pa_bool_t enabled;
1044
1045       if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1046         !pa_tagstruct_eof(t))
1047         goto fail;
1048
1049       if (enabled)
1050         pa_idxset_put(u->subscribed, c, NULL);
1051       else
1052         pa_idxset_remove_by_data(u->subscribed, c, NULL);
1053
1054       break;
1055     }
1056
1057     default:
1058       goto fail;
1059   }
1060
1061   pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1062   return 0;
1063
1064   fail:
1065
1066   if (reply)
1067     pa_tagstruct_free(reply);
1068
1069   return -1;
1070 }
1071
1072 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
1073     pa_assert(p);
1074     pa_assert(c);
1075     pa_assert(u);
1076
1077     pa_idxset_remove_by_data(u->subscribed, c, NULL);
1078     return PA_HOOK_OK;
1079 }
1080
1081 int pa__init(pa_module*m) {
1082     pa_modargs *ma = NULL;
1083     struct userdata *u;
1084     char *fname;
1085     pa_sink *sink;
1086     pa_source *source;
1087     pa_sink_input *si;
1088     pa_source_output *so;
1089     uint32_t idx;
1090     pa_bool_t do_routing = FALSE, on_hotplug = TRUE, on_rescue = TRUE;
1091
1092     pa_assert(m);
1093
1094     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1095         pa_log("Failed to parse module arguments");
1096         goto fail;
1097     }
1098
1099     if (pa_modargs_get_value_boolean(ma, "do_routing", &do_routing) < 0 ||
1100         pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
1101         pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
1102         pa_log("on_hotplug= and on_rescue= expect boolean arguments");
1103         goto fail;
1104     }
1105
1106     m->userdata = u = pa_xnew0(struct userdata, 1);
1107     u->core = m->core;
1108     u->module = m;
1109     u->do_routing = do_routing;
1110     u->on_hotplug = on_hotplug;
1111     u->on_rescue = on_rescue;
1112     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1113
1114     u->protocol = pa_native_protocol_get(m->core);
1115     pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1116
1117     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);
1118
1119     u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
1120
1121     /* Used to handle device description management */
1122     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);
1123     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);
1124
1125     /* The following slots are used to deal with routing */
1126     /* A little bit later than module-stream-restore, module-intended-roles */
1127     u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY+15, (pa_hook_cb_t) sink_input_new_hook_callback, u);
1128     u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY+15, (pa_hook_cb_t) source_output_new_hook_callback, u);
1129
1130     if (on_hotplug) {
1131         /* A little bit later than module-stream-restore, module-intended-roles */
1132         u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+15, (pa_hook_cb_t) sink_put_hook_callback, u);
1133         u->source_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+15, (pa_hook_cb_t) source_put_hook_callback, u);
1134     }
1135
1136     if (on_rescue) {
1137         /* A little bit later than module-stream-restore, module-intended-roles, a little bit earlier than module-rescue-streams, ... */
1138         u->sink_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+15, (pa_hook_cb_t) sink_unlink_hook_callback, u);
1139         u->source_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+15, (pa_hook_cb_t) source_unlink_hook_callback, u);
1140     }
1141
1142     if (!(fname = pa_state_path("device-manager", TRUE)))
1143         goto fail;
1144
1145     if (!(u->database = pa_database_open(fname, TRUE))) {
1146         pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
1147         pa_xfree(fname);
1148         goto fail;
1149     }
1150
1151     pa_log_info("Sucessfully opened database file '%s'.", fname);
1152     pa_xfree(fname);
1153
1154     PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
1155         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
1156
1157     PA_IDXSET_FOREACH(source, m->core->sources, idx)
1158         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
1159
1160     PA_IDXSET_FOREACH(si, m->core->sink_inputs, idx)
1161         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, si->index, u);
1162
1163     PA_IDXSET_FOREACH(so, m->core->source_outputs, idx)
1164         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, so->index, u);
1165
1166     pa_modargs_free(ma);
1167     return 0;
1168
1169 fail:
1170     pa__done(m);
1171
1172     if (ma)
1173         pa_modargs_free(ma);
1174
1175     return  -1;
1176 }
1177
1178 void pa__done(pa_module*m) {
1179     struct userdata* u;
1180
1181     pa_assert(m);
1182
1183     if (!(u = m->userdata))
1184         return;
1185
1186     if (u->subscription)
1187         pa_subscription_free(u->subscription);
1188
1189     if (u->sink_new_hook_slot)
1190         pa_hook_slot_free(u->sink_new_hook_slot);
1191     if (u->source_new_hook_slot)
1192         pa_hook_slot_free(u->source_new_hook_slot);
1193
1194     if (u->sink_input_new_hook_slot)
1195         pa_hook_slot_free(u->sink_input_new_hook_slot);
1196     if (u->source_output_new_hook_slot)
1197         pa_hook_slot_free(u->source_output_new_hook_slot);
1198
1199     if (u->sink_put_hook_slot)
1200         pa_hook_slot_free(u->sink_put_hook_slot);
1201     if (u->source_put_hook_slot)
1202         pa_hook_slot_free(u->source_put_hook_slot);
1203
1204     if (u->sink_unlink_hook_slot)
1205         pa_hook_slot_free(u->sink_unlink_hook_slot);
1206     if (u->source_unlink_hook_slot)
1207         pa_hook_slot_free(u->source_unlink_hook_slot);
1208
1209     if (u->save_time_event)
1210         u->core->mainloop->time_free(u->save_time_event);
1211
1212     if (u->database)
1213         pa_database_close(u->database);
1214
1215     if (u->protocol) {
1216         pa_native_protocol_remove_ext(u->protocol, m);
1217         pa_native_protocol_unref(u->protocol);
1218     }
1219
1220     if (u->subscribed)
1221         pa_idxset_free(u->subscribed, NULL, NULL);
1222
1223     pa_xfree(u);
1224 }