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