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