]> code.delx.au - pulseaudio/blob - src/modules/module-device-manager.c
device-manager: Remove unneeded logic for checking for and (un)loading module-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 "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 pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
406 char *name;
407 struct entry *e;
408
409 pa_assert(c);
410 pa_assert(new_data);
411 pa_assert(u);
412
413 if (!u->role_device_priority_routing)
414 return PA_HOOK_OK;
415
416 /*if (!(name = get_name(new_data->proplist, "sink-input")))
417 return PA_HOOK_OK;
418
419 if (new_data->sink)
420 pa_log_debug("Not restoring device for stream %s, because already set.", name);
421 else if ((e = read_entry(u, name))) {
422
423 pa_xfree(e);
424 }
425
426 pa_xfree(name);*/
427
428 return PA_HOOK_OK;
429 }
430
431 static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
432 char *name;
433 struct entry *e;
434
435 pa_assert(c);
436 pa_assert(new_data);
437 pa_assert(u);
438
439 if (!u->role_device_priority_routing)
440 return PA_HOOK_OK;
441
442 if (new_data->direct_on_input)
443 return PA_HOOK_OK;
444
445 /*if (!(name = get_name(new_data->proplist, "source-output")))
446 return PA_HOOK_OK;
447
448 if (new_data->source)
449 pa_log_debug("Not restoring device for stream %s, because already set", name);
450 else if ((e = read_entry(u, name))) {
451
452 pa_xfree(e);
453 }
454
455 pa_xfree(name);*/
456
457 return PA_HOOK_OK;
458 }
459
460 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
461 pa_sink_input *si;
462 uint32_t idx;
463
464 pa_assert(c);
465 pa_assert(sink);
466 pa_assert(u);
467 pa_assert(u->on_hotplug);
468
469 if (!u->role_device_priority_routing)
470 return PA_HOOK_OK;
471
472 /** @todo Ensure redo the routing based on the priorities */
473
474 return PA_HOOK_OK;
475 }
476
477 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
478 pa_source_output *so;
479 uint32_t idx;
480
481 pa_assert(c);
482 pa_assert(source);
483 pa_assert(u);
484 pa_assert(u->on_hotplug);
485
486 if (!u->role_device_priority_routing)
487 return PA_HOOK_OK;
488
489 /** @todo Ensure redo the routing based on the priorities */
490
491 return PA_HOOK_OK;
492 }
493
494 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
495 pa_sink_input *si;
496 uint32_t idx;
497
498 pa_assert(c);
499 pa_assert(sink);
500 pa_assert(u);
501 pa_assert(u->on_rescue);
502
503 /* There's no point in doing anything if the core is shut down anyway */
504 if (c->state == PA_CORE_SHUTDOWN)
505 return PA_HOOK_OK;
506
507 if (!u->role_device_priority_routing)
508 return PA_HOOK_OK;
509
510 /** @todo Ensure redo the routing based on the priorities */
511
512 return PA_HOOK_OK;
513 }
514
515 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
516 pa_source_output *so;
517 uint32_t idx;
518
519 pa_assert(c);
520 pa_assert(source);
521 pa_assert(u);
522 pa_assert(u->on_rescue);
523
524 /* There's no point in doing anything if the core is shut down anyway */
525 if (c->state == PA_CORE_SHUTDOWN)
526 return PA_HOOK_OK;
527
528 if (!u->role_device_priority_routing)
529 return PA_HOOK_OK;
530
531 /** @todo Ensure redo the routing based on the priorities */
532
533 return PA_HOOK_OK;
534 }
535
536
537 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
538 pa_sink *sink;
539 pa_source *source;
540 uint32_t idx;
541 char *n;
542
543 pa_assert(u);
544 pa_assert(name);
545 pa_assert(e);
546
547 if ((n = get_name(name, "sink:"))) {
548 for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) {
549 if (!pa_streq(sink->name, n)) {
550 continue;
551 }
552
553 pa_log_info("Setting description for sink %s.", sink->name);
554 pa_sink_set_description(sink, e->description);
555 }
556 pa_xfree(n);
557 }
558 else if ((n = get_name(name, "source:"))) {
559 for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) {
560 if (!pa_streq(source->name, n)) {
561 continue;
562 }
563
564 if (source->monitor_of) {
565 pa_log_warn("Cowardly refusing to set the description for monitor source %s.", source->name);
566 continue;
567 }
568
569 pa_log_info("Setting description for source %s.", source->name);
570 pa_source_set_description(source, e->description);
571 }
572 pa_xfree(n);
573 }
574 }
575
576
577 static uint32_t get_role_index(const char* role) {
578 pa_assert(role);
579
580 if (strcmp(role, "") == 0)
581 return ROLE_NONE;
582 if (strcmp(role, "video") == 0)
583 return ROLE_VIDEO;
584 if (strcmp(role, "music") == 0)
585 return ROLE_MUSIC;
586 if (strcmp(role, "game") == 0)
587 return ROLE_GAME;
588 if (strcmp(role, "event") == 0)
589 return ROLE_EVENT;
590 if (strcmp(role, "phone") == 0)
591 return ROLE_PHONE;
592 if (strcmp(role, "animation") == 0)
593 return ROLE_ANIMATION;
594 if (strcmp(role, "production") == 0)
595 return ROLE_PRODUCTION;
596 if (strcmp(role, "a11y") == 0)
597 return ROLE_A11Y;
598 return PA_INVALID_INDEX;
599 }
600
601 #define EXT_VERSION 1
602
603 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
604 struct userdata *u;
605 uint32_t command;
606 pa_tagstruct *reply = NULL;
607
608 pa_assert(p);
609 pa_assert(m);
610 pa_assert(c);
611 pa_assert(t);
612
613 u = m->userdata;
614
615 if (pa_tagstruct_getu32(t, &command) < 0)
616 goto fail;
617
618 reply = pa_tagstruct_new(NULL, 0);
619 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
620 pa_tagstruct_putu32(reply, tag);
621
622 switch (command) {
623 case SUBCOMMAND_TEST: {
624 if (!pa_tagstruct_eof(t))
625 goto fail;
626
627 pa_tagstruct_putu32(reply, EXT_VERSION);
628 break;
629 }
630
631 case SUBCOMMAND_READ: {
632 pa_datum key;
633 pa_bool_t done;
634
635 if (!pa_tagstruct_eof(t))
636 goto fail;
637
638 done = !pa_database_first(u->database, &key, NULL);
639
640 while (!done) {
641 pa_datum next_key;
642 struct entry *e;
643 char *name;
644
645 done = !pa_database_next(u->database, &key, &next_key, NULL);
646
647 name = pa_xstrndup(key.data, key.size);
648 pa_datum_free(&key);
649
650 if ((e = read_entry(u, name))) {
651 pa_tagstruct_puts(reply, name);
652 pa_tagstruct_puts(reply, e->description);
653
654 pa_xfree(e);
655 }
656
657 pa_xfree(name);
658
659 key = next_key;
660 }
661
662 break;
663 }
664
665 case SUBCOMMAND_RENAME: {
666
667 struct entry *e;
668 const char *device, *description;
669
670 if (pa_tagstruct_gets(t, &device) < 0 ||
671 pa_tagstruct_gets(t, &description) < 0)
672 goto fail;
673
674 if (!device || !*device || !description || !*description)
675 goto fail;
676
677 if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
678 pa_datum key, data;
679
680 pa_strlcpy(e->description, description, sizeof(e->description));
681
682 key.data = (char *) device;
683 key.size = strlen(device);
684
685 data.data = e;
686 data.size = sizeof(*e);
687
688 if (pa_database_set(u->database, &key, &data, FALSE) == 0) {
689 apply_entry(u, device, e);
690
691 trigger_save(u);
692 }
693 else
694 pa_log_warn("Could not save device");
695
696 pa_xfree(e);
697 }
698 else
699 pa_log_warn("Could not rename device %s, no entry in database", device);
700
701 break;
702 }
703
704 case SUBCOMMAND_DELETE:
705
706 while (!pa_tagstruct_eof(t)) {
707 const char *name;
708 pa_datum key;
709
710 if (pa_tagstruct_gets(t, &name) < 0)
711 goto fail;
712
713 key.data = (char*) name;
714 key.size = strlen(name);
715
716 /** @todo: Reindex the priorities */
717 pa_database_unset(u->database, &key);
718 }
719
720 trigger_save(u);
721
722 break;
723
724 case SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING: {
725
726 pa_bool_t enable;
727 uint32_t sridx = PA_INVALID_INDEX;
728 uint32_t idx;
729 pa_module *module;
730
731 if (pa_tagstruct_get_boolean(t, &enable) < 0)
732 goto fail;
733
734 u->role_device_priority_routing = enable;
735
736 break;
737 }
738
739 case SUBCOMMAND_PREFER_DEVICE:
740 case SUBCOMMAND_DEFER_DEVICE: {
741
742 const char *role, *device;
743 struct entry *e;
744 uint32_t role_index;
745
746 if (pa_tagstruct_gets(t, &role) < 0 ||
747 pa_tagstruct_gets(t, &device) < 0)
748 goto fail;
749
750 if (!role || !device || !*device)
751 goto fail;
752
753 role_index = get_role_index(role);
754 if (PA_INVALID_INDEX == role_index)
755 goto fail;
756
757 if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
758 pa_datum key, data;
759 pa_bool_t done;
760 char* prefix;
761 uint32_t priority;
762 pa_bool_t haschanged = FALSE;
763
764 if (strncmp(device, "sink:", 5) == 0)
765 prefix = pa_xstrdup("sink:");
766 else
767 prefix = pa_xstrdup("source:");
768
769 priority = e->priority[role_index];
770
771 /* Now we need to load up all the other entries of this type and shuffle the priroities around */
772
773 done = !pa_database_first(u->database, &key, NULL);
774
775 while (!done && !haschanged) {
776 pa_datum next_key;
777
778 done = !pa_database_next(u->database, &key, &next_key, NULL);
779
780 /* Only read devices with the right prefix */
781 if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
782 char *name;
783 struct entry *e2;
784
785 name = pa_xstrndup(key.data, key.size);
786
787 if ((e2 = read_entry(u, name))) {
788 if (SUBCOMMAND_PREFER_DEVICE == command) {
789 /* PREFER */
790 if (e2->priority[role_index] == (priority - 1)) {
791 e2->priority[role_index]++;
792 haschanged = TRUE;
793 }
794 } else {
795 /* DEFER */
796 if (e2->priority[role_index] == (priority + 1)) {
797 e2->priority[role_index]--;
798 haschanged = TRUE;
799 }
800 }
801
802 if (haschanged) {
803 data.data = e2;
804 data.size = sizeof(*e2);
805
806 if (pa_database_set(u->database, &key, &data, FALSE))
807 pa_log_warn("Could not save device");
808 }
809
810 pa_xfree(e2);
811 }
812
813 pa_xfree(name);
814 }
815
816 pa_datum_free(&key);
817 key = next_key;
818 }
819
820 /* Now write out our actual entry */
821 if (haschanged) {
822 if (SUBCOMMAND_PREFER_DEVICE == command)
823 e->priority[role_index]--;
824 else
825 e->priority[role_index]++;
826
827 key.data = (char *) device;
828 key.size = strlen(device);
829
830 data.data = e;
831 data.size = sizeof(*e);
832
833 if (pa_database_set(u->database, &key, &data, FALSE))
834 pa_log_warn("Could not save device");
835
836 trigger_save(u);
837 }
838
839 pa_xfree(e);
840
841 pa_xfree(prefix);
842 }
843 else
844 pa_log_warn("Could not reorder device %s, no entry in database", device);
845
846 break;
847 }
848
849 case SUBCOMMAND_SUBSCRIBE: {
850
851 pa_bool_t enabled;
852
853 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
854 !pa_tagstruct_eof(t))
855 goto fail;
856
857 if (enabled)
858 pa_idxset_put(u->subscribed, c, NULL);
859 else
860 pa_idxset_remove_by_data(u->subscribed, c, NULL);
861
862 break;
863 }
864
865 default:
866 goto fail;
867 }
868
869 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
870 return 0;
871
872 fail:
873
874 if (reply)
875 pa_tagstruct_free(reply);
876
877 return -1;
878 }
879
880 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
881 pa_assert(p);
882 pa_assert(c);
883 pa_assert(u);
884
885 pa_idxset_remove_by_data(u->subscribed, c, NULL);
886 return PA_HOOK_OK;
887 }
888
889 int pa__init(pa_module*m) {
890 pa_modargs *ma = NULL;
891 struct userdata *u;
892 char *fname;
893 pa_sink *sink;
894 pa_source *source;
895 pa_sink_input *si;
896 pa_source_output *so;
897 uint32_t idx;
898 pa_bool_t on_hotplug = TRUE, on_rescue = TRUE;
899
900 pa_assert(m);
901
902 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
903 pa_log("Failed to parse module arguments");
904 goto fail;
905 }
906
907 if (pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
908 pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
909 pa_log("on_hotplug= and on_rescue= expect boolean arguments");
910 goto fail;
911 }
912
913 m->userdata = u = pa_xnew0(struct userdata, 1);
914 u->core = m->core;
915 u->module = m;
916 u->on_hotplug = on_hotplug;
917 u->on_rescue = on_rescue;
918 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
919
920 u->protocol = pa_native_protocol_get(m->core);
921 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
922
923 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);
924
925 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
926
927 /* Used to handle device description management */
928 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);
929 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);
930
931 /* The following slots are used to deal with routing */
932 /* A little bit later than module-stream-restore, module-intended-roles */
933 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);
934 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);
935
936 if (on_hotplug) {
937 /* A little bit later than module-stream-restore, module-intended-roles */
938 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);
939 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);
940 }
941
942 if (on_rescue) {
943 /* A little bit later than module-stream-restore, module-intended-roles, a little bit earlier than module-rescue-streams, ... */
944 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);
945 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);
946 }
947
948 if (!(fname = pa_state_path("device-manager", TRUE)))
949 goto fail;
950
951 if (!(u->database = pa_database_open(fname, TRUE))) {
952 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
953 pa_xfree(fname);
954 goto fail;
955 }
956
957 pa_log_info("Sucessfully opened database file '%s'.", fname);
958 pa_xfree(fname);
959
960 PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
961 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
962
963 PA_IDXSET_FOREACH(source, m->core->sources, idx)
964 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
965
966 PA_IDXSET_FOREACH(si, m->core->sink_inputs, idx)
967 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, si->index, u);
968
969 PA_IDXSET_FOREACH(so, m->core->source_outputs, idx)
970 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, so->index, u);
971
972 pa_modargs_free(ma);
973 return 0;
974
975 fail:
976 pa__done(m);
977
978 if (ma)
979 pa_modargs_free(ma);
980
981 return -1;
982 }
983
984 void pa__done(pa_module*m) {
985 struct userdata* u;
986
987 pa_assert(m);
988
989 if (!(u = m->userdata))
990 return;
991
992 if (u->subscription)
993 pa_subscription_free(u->subscription);
994
995 if (u->sink_new_hook_slot)
996 pa_hook_slot_free(u->sink_new_hook_slot);
997 if (u->source_new_hook_slot)
998 pa_hook_slot_free(u->source_new_hook_slot);
999
1000 if (u->sink_input_new_hook_slot)
1001 pa_hook_slot_free(u->sink_input_new_hook_slot);
1002 if (u->source_output_new_hook_slot)
1003 pa_hook_slot_free(u->source_output_new_hook_slot);
1004
1005 if (u->sink_put_hook_slot)
1006 pa_hook_slot_free(u->sink_put_hook_slot);
1007 if (u->source_put_hook_slot)
1008 pa_hook_slot_free(u->source_put_hook_slot);
1009
1010 if (u->sink_unlink_hook_slot)
1011 pa_hook_slot_free(u->sink_unlink_hook_slot);
1012 if (u->source_unlink_hook_slot)
1013 pa_hook_slot_free(u->source_unlink_hook_slot);
1014
1015 if (u->save_time_event)
1016 u->core->mainloop->time_free(u->save_time_event);
1017
1018 if (u->database)
1019 pa_database_close(u->database);
1020
1021 if (u->protocol) {
1022 pa_native_protocol_remove_ext(u->protocol, m);
1023 pa_native_protocol_unref(u->protocol);
1024 }
1025
1026 if (u->subscribed)
1027 pa_idxset_free(u->subscribed, NULL, NULL);
1028
1029 pa_xfree(u);
1030 }