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