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