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