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