core: split of FAIL_ON_SUSPEND into KILL_ON_SUSPEND and NO_CREATE_ON_SUSPEND
[pulseaudio-mirror.git] / src / modules / module-stream-restore.c
blob727a52752fb5b78513a9829305b5a9f8ee5189a3
1 /***
2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
34 #include <pulse/xmalloc.h>
35 #include <pulse/volume.h>
36 #include <pulse/timeval.h>
37 #include <pulse/util.h>
38 #include <pulse/rtclock.h>
40 #include <pulsecore/core-error.h>
41 #include <pulsecore/module.h>
42 #include <pulsecore/core-util.h>
43 #include <pulsecore/modargs.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/core-subscribe.h>
46 #include <pulsecore/sink-input.h>
47 #include <pulsecore/source-output.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/protocol-native.h>
50 #include <pulsecore/pstream.h>
51 #include <pulsecore/pstream-util.h>
52 #include <pulsecore/database.h>
54 #include "module-stream-restore-symdef.h"
56 PA_MODULE_AUTHOR("Lennart Poettering");
57 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute/device state of streams");
58 PA_MODULE_VERSION(PACKAGE_VERSION);
59 PA_MODULE_LOAD_ONCE(TRUE);
60 PA_MODULE_USAGE(
61 "restore_device=<Save/restore sinks/sources?> "
62 "restore_volume=<Save/restore volumes?> "
63 "restore_muted=<Save/restore muted states?> "
64 "on_hotplug=<When new device becomes available, recheck streams?> "
65 "on_rescue=<When device becomes unavailable, recheck streams?>");
67 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
68 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
70 static const char* const valid_modargs[] = {
71 "restore_device",
72 "restore_volume",
73 "restore_muted",
74 "on_hotplug",
75 "on_rescue",
76 NULL
79 struct userdata {
80 pa_core *core;
81 pa_module *module;
82 pa_subscription *subscription;
83 pa_hook_slot
84 *sink_input_new_hook_slot,
85 *sink_input_fixate_hook_slot,
86 *source_output_new_hook_slot,
87 *sink_put_hook_slot,
88 *source_put_hook_slot,
89 *sink_unlink_hook_slot,
90 *source_unlink_hook_slot,
91 *connection_unlink_hook_slot;
92 pa_time_event *save_time_event;
93 pa_database* database;
95 pa_bool_t restore_device:1;
96 pa_bool_t restore_volume:1;
97 pa_bool_t restore_muted:1;
98 pa_bool_t on_hotplug:1;
99 pa_bool_t on_rescue:1;
101 pa_native_protocol *protocol;
102 pa_idxset *subscribed;
105 #define ENTRY_VERSION 3
107 struct entry {
108 uint8_t version;
109 pa_bool_t muted_valid:1, volume_valid:1, device_valid:1, card_valid:1;
110 pa_bool_t muted:1;
111 pa_channel_map channel_map;
112 pa_cvolume volume;
113 char device[PA_NAME_MAX];
114 char card[PA_NAME_MAX];
115 } PA_GCC_PACKED;
117 enum {
118 SUBCOMMAND_TEST,
119 SUBCOMMAND_READ,
120 SUBCOMMAND_WRITE,
121 SUBCOMMAND_DELETE,
122 SUBCOMMAND_SUBSCRIBE,
123 SUBCOMMAND_EVENT
126 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
127 struct userdata *u = userdata;
129 pa_assert(a);
130 pa_assert(e);
131 pa_assert(u);
133 pa_assert(e == u->save_time_event);
134 u->core->mainloop->time_free(u->save_time_event);
135 u->save_time_event = NULL;
137 pa_database_sync(u->database);
138 pa_log_info("Synced.");
141 static char *get_name(pa_proplist *p, const char *prefix) {
142 const char *r;
143 char *t;
145 if (!p)
146 return NULL;
148 if ((r = pa_proplist_gets(p, IDENTIFICATION_PROPERTY)))
149 return pa_xstrdup(r);
151 if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_ROLE)))
152 t = pa_sprintf_malloc("%s-by-media-role:%s", prefix, r);
153 else if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_ID)))
154 t = pa_sprintf_malloc("%s-by-application-id:%s", prefix, r);
155 else if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_NAME)))
156 t = pa_sprintf_malloc("%s-by-application-name:%s", prefix, r);
157 else if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_NAME)))
158 t = pa_sprintf_malloc("%s-by-media-name:%s", prefix, r);
159 else
160 t = pa_sprintf_malloc("%s-fallback:%s", prefix, r);
162 pa_proplist_sets(p, IDENTIFICATION_PROPERTY, t);
163 return t;
166 static struct entry* read_entry(struct userdata *u, const char *name) {
167 pa_datum key, data;
168 struct entry *e;
170 pa_assert(u);
171 pa_assert(name);
173 key.data = (char*) name;
174 key.size = strlen(name);
176 pa_zero(data);
178 if (!pa_database_get(u->database, &key, &data))
179 goto fail;
181 if (data.size != sizeof(struct entry)) {
182 /* This is probably just a database upgrade, hence let's not
183 * consider this more than a debug message */
184 pa_log_debug("Database contains entry for stream %s of wrong size %lu != %lu. Probably due to uprade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry));
185 goto fail;
188 e = (struct entry*) data.data;
190 if (e->version != ENTRY_VERSION) {
191 pa_log_debug("Version of database entry for stream %s doesn't match our version. Probably due to upgrade, ignoring.", name);
192 goto fail;
195 if (!memchr(e->device, 0, sizeof(e->device))) {
196 pa_log_warn("Database contains entry for stream %s with missing NUL byte in device name", name);
197 goto fail;
200 if (!memchr(e->card, 0, sizeof(e->card))) {
201 pa_log_warn("Database contains entry for stream %s with missing NUL byte in card name", name);
202 goto fail;
205 if (e->device_valid && !pa_namereg_is_valid_name(e->device)) {
206 pa_log_warn("Invalid device name stored in database for stream %s", name);
207 goto fail;
210 if (e->card_valid && !pa_namereg_is_valid_name(e->card)) {
211 pa_log_warn("Invalid card name stored in database for stream %s", name);
212 goto fail;
215 if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
216 pa_log_warn("Invalid channel map stored in database for stream %s", name);
217 goto fail;
220 if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
221 pa_log_warn("Invalid volume stored in database for stream %s", name);
222 goto fail;
225 return e;
227 fail:
229 pa_datum_free(&data);
230 return NULL;
233 static void trigger_save(struct userdata *u) {
234 pa_native_connection *c;
235 uint32_t idx;
237 for (c = pa_idxset_first(u->subscribed, &idx); c; c = pa_idxset_next(u->subscribed, &idx)) {
238 pa_tagstruct *t;
240 t = pa_tagstruct_new(NULL, 0);
241 pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
242 pa_tagstruct_putu32(t, 0);
243 pa_tagstruct_putu32(t, u->module->index);
244 pa_tagstruct_puts(t, u->module->name);
245 pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
247 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
250 if (u->save_time_event)
251 return;
253 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
256 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
257 pa_cvolume t;
259 pa_assert(a);
260 pa_assert(b);
262 if (a->device_valid != b->device_valid ||
263 (a->device_valid && strncmp(a->device, b->device, sizeof(a->device))))
264 return FALSE;
266 if (a->card_valid != b->card_valid ||
267 (a->card_valid && strncmp(a->card, b->card, sizeof(a->card))))
268 return FALSE;
270 if (a->muted_valid != b->muted_valid ||
271 (a->muted_valid && (a->muted != b->muted)))
272 return FALSE;
274 t = b->volume;
275 if (a->volume_valid != b->volume_valid ||
276 (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
277 return FALSE;
279 return TRUE;
282 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
283 struct userdata *u = userdata;
284 struct entry entry, *old;
285 char *name;
286 pa_datum key, data;
288 pa_assert(c);
289 pa_assert(u);
291 if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
292 t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
293 t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
294 t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE))
295 return;
297 pa_zero(entry);
298 entry.version = ENTRY_VERSION;
300 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
301 pa_sink_input *sink_input;
303 if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx)))
304 return;
306 if (!(name = get_name(sink_input->proplist, "sink-input")))
307 return;
309 if ((old = read_entry(u, name)))
310 entry = *old;
312 if (sink_input->save_volume) {
313 entry.channel_map = sink_input->channel_map;
314 pa_sink_input_get_volume(sink_input, &entry.volume, FALSE);
315 entry.volume_valid = TRUE;
318 if (sink_input->save_muted) {
319 entry.muted = pa_sink_input_get_mute(sink_input);
320 entry.muted_valid = TRUE;
323 if (sink_input->save_sink) {
324 pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device));
325 entry.device_valid = TRUE;
327 if (sink_input->sink->card) {
328 pa_strlcpy(entry.card, sink_input->sink->card->name, sizeof(entry.card));
329 entry.card_valid = TRUE;
333 } else {
334 pa_source_output *source_output;
336 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT);
338 if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx)))
339 return;
341 if (!(name = get_name(source_output->proplist, "source-output")))
342 return;
344 if ((old = read_entry(u, name)))
345 entry = *old;
347 if (source_output->save_source) {
348 pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device));
349 entry.device_valid = source_output->save_source;
351 if (source_output->source->card) {
352 pa_strlcpy(entry.card, source_output->source->card->name, sizeof(entry.card));
353 entry.card_valid = TRUE;
358 if (old) {
360 if (entries_equal(old, &entry)) {
361 pa_xfree(old);
362 pa_xfree(name);
363 return;
366 pa_xfree(old);
369 key.data = name;
370 key.size = strlen(name);
372 data.data = &entry;
373 data.size = sizeof(entry);
375 pa_log_info("Storing volume/mute/device for stream %s.", name);
377 pa_database_set(u->database, &key, &data, TRUE);
379 pa_xfree(name);
381 trigger_save(u);
384 static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
385 char *name;
386 struct entry *e;
388 pa_assert(c);
389 pa_assert(new_data);
390 pa_assert(u);
391 pa_assert(u->restore_device);
393 if (!(name = get_name(new_data->proplist, "sink-input")))
394 return PA_HOOK_OK;
396 if (new_data->sink)
397 pa_log_debug("Not restoring device for stream %s, because already set.", name);
398 else if ((e = read_entry(u, name))) {
399 pa_sink *s = NULL;
401 if (e->device_valid)
402 s = pa_namereg_get(c, e->device, PA_NAMEREG_SINK);
404 if (!s && e->card_valid) {
405 pa_card *card;
407 if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD)))
408 s = pa_idxset_first(card->sinks, NULL);
411 /* It might happen that a stream and a sink are set up at the
412 same time, in which case we want to make sure we don't
413 interfere with that */
414 if (s && PA_SINK_IS_LINKED(pa_sink_get_state(s))) {
415 pa_log_info("Restoring device for stream %s.", name);
416 new_data->sink = s;
417 new_data->save_sink = TRUE;
420 pa_xfree(e);
423 pa_xfree(name);
425 return PA_HOOK_OK;
428 static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
429 char *name;
430 struct entry *e;
432 pa_assert(c);
433 pa_assert(new_data);
434 pa_assert(u);
435 pa_assert(u->restore_volume || u->restore_muted);
437 if (!(name = get_name(new_data->proplist, "sink-input")))
438 return PA_HOOK_OK;
440 if ((e = read_entry(u, name))) {
442 if (u->restore_volume && e->volume_valid) {
444 if (!new_data->volume_is_set) {
445 pa_cvolume v;
447 pa_log_info("Restoring volume for sink input %s.", name);
449 v = e->volume;
450 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
451 pa_sink_input_new_data_set_volume(new_data, &v);
453 new_data->volume_is_absolute = FALSE;
454 new_data->save_volume = TRUE;
455 } else
456 pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
459 if (u->restore_muted && e->muted_valid) {
461 if (!new_data->muted_is_set) {
462 pa_log_info("Restoring mute state for sink input %s.", name);
463 pa_sink_input_new_data_set_muted(new_data, e->muted);
464 new_data->save_muted = TRUE;
465 } else
466 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name);
469 pa_xfree(e);
472 pa_xfree(name);
474 return PA_HOOK_OK;
477 static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
478 char *name;
479 struct entry *e;
481 pa_assert(c);
482 pa_assert(new_data);
483 pa_assert(u);
484 pa_assert(u->restore_device);
486 if (new_data->direct_on_input)
487 return PA_HOOK_OK;
489 if (!(name = get_name(new_data->proplist, "source-output")))
490 return PA_HOOK_OK;
492 if (new_data->source)
493 pa_log_debug("Not restoring device for stream %s, because already set", name);
494 else if ((e = read_entry(u, name))) {
495 pa_source *s = NULL;
497 if (e->device_valid)
498 s = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE);
500 if (!s && e->card_valid) {
501 pa_card *card;
503 if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD)))
504 s = pa_idxset_first(card->sources, NULL);
507 /* It might happen that a stream and a sink are set up at the
508 same time, in which case we want to make sure we don't
509 interfere with that */
510 if (s && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) {
511 pa_log_info("Restoring device for stream %s.", name);
512 new_data->source = s;
513 new_data->save_source = TRUE;
516 pa_xfree(e);
519 pa_xfree(name);
521 return PA_HOOK_OK;
524 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
525 pa_sink_input *si;
526 uint32_t idx;
528 pa_assert(c);
529 pa_assert(sink);
530 pa_assert(u);
531 pa_assert(u->on_hotplug && u->restore_device);
533 PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
534 char *name;
535 struct entry *e;
537 if (si->sink == sink)
538 continue;
540 if (si->save_sink)
541 continue;
543 /* It might happen that a stream and a sink are set up at the
544 same time, in which case we want to make sure we don't
545 interfere with that */
546 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
547 continue;
549 if (!(name = get_name(si->proplist, "sink-input")))
550 continue;
552 if ((e = read_entry(u, name))) {
553 if (e->device_valid && pa_streq(e->device, sink->name))
554 pa_sink_input_move_to(si, sink, TRUE);
556 pa_xfree(e);
559 pa_xfree(name);
562 return PA_HOOK_OK;
565 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
566 pa_source_output *so;
567 uint32_t idx;
569 pa_assert(c);
570 pa_assert(source);
571 pa_assert(u);
572 pa_assert(u->on_hotplug && u->restore_device);
574 PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
575 char *name;
576 struct entry *e;
578 if (so->source == source)
579 continue;
581 if (so->save_source)
582 continue;
584 if (so->direct_on_input)
585 continue;
587 /* It might happen that a stream and a sink are set up at the
588 same time, in which case we want to make sure we don't
589 interfere with that */
590 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
591 continue;
593 if (!(name = get_name(so->proplist, "source-input")))
594 continue;
596 if ((e = read_entry(u, name))) {
597 if (e->device_valid && pa_streq(e->device, source->name))
598 pa_source_output_move_to(so, source, TRUE);
600 pa_xfree(e);
603 pa_xfree(name);
606 return PA_HOOK_OK;
609 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
610 pa_sink_input *si;
611 uint32_t idx;
613 pa_assert(c);
614 pa_assert(sink);
615 pa_assert(u);
616 pa_assert(u->on_rescue && u->restore_device);
618 /* There's no point in doing anything if the core is shut down anyway */
619 if (c->state == PA_CORE_SHUTDOWN)
620 return PA_HOOK_OK;
622 PA_IDXSET_FOREACH(si, sink->inputs, idx) {
623 char *name;
624 struct entry *e;
626 if (!(name = get_name(si->proplist, "sink-input")))
627 continue;
629 if ((e = read_entry(u, name))) {
631 if (e->device_valid) {
632 pa_sink *d;
634 if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) &&
635 d != sink &&
636 PA_SINK_IS_LINKED(pa_sink_get_state(d)))
637 pa_sink_input_move_to(si, d, TRUE);
640 pa_xfree(e);
643 pa_xfree(name);
646 return PA_HOOK_OK;
649 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
650 pa_source_output *so;
651 uint32_t idx;
653 pa_assert(c);
654 pa_assert(source);
655 pa_assert(u);
656 pa_assert(u->on_rescue && u->restore_device);
658 /* There's no point in doing anything if the core is shut down anyway */
659 if (c->state == PA_CORE_SHUTDOWN)
660 return PA_HOOK_OK;
662 PA_IDXSET_FOREACH(so, source->outputs, idx) {
663 char *name;
664 struct entry *e;
666 if (!(name = get_name(so->proplist, "source-output")))
667 continue;
669 if ((e = read_entry(u, name))) {
671 if (e->device_valid) {
672 pa_source *d;
674 if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) &&
675 d != source &&
676 PA_SOURCE_IS_LINKED(pa_source_get_state(d)))
677 pa_source_output_move_to(so, d, TRUE);
680 pa_xfree(e);
683 pa_xfree(name);
686 return PA_HOOK_OK;
689 #define EXT_VERSION 1
691 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
692 pa_sink_input *si;
693 pa_source_output *so;
694 uint32_t idx;
696 pa_assert(u);
697 pa_assert(name);
698 pa_assert(e);
700 PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
701 char *n;
702 pa_sink *s;
704 if (!(n = get_name(si->proplist, "sink-input")))
705 continue;
707 if (!pa_streq(name, n)) {
708 pa_xfree(n);
709 continue;
711 pa_xfree(n);
713 if (u->restore_volume && e->volume_valid) {
714 pa_cvolume v;
716 v = e->volume;
717 pa_log_info("Restoring volume for sink input %s.", name);
718 pa_cvolume_remap(&v, &e->channel_map, &si->channel_map);
719 pa_sink_input_set_volume(si, &v, TRUE, FALSE);
722 if (u->restore_muted && e->muted_valid) {
723 pa_log_info("Restoring mute state for sink input %s.", name);
724 pa_sink_input_set_mute(si, e->muted, TRUE);
727 if (u->restore_device &&
728 e->device_valid &&
729 (s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SINK))) {
731 pa_log_info("Restoring device for stream %s.", name);
732 pa_sink_input_move_to(si, s, TRUE);
736 PA_IDXSET_FOREACH(so, u->core->source_outputs, idx) {
737 char *n;
738 pa_source *s;
740 if (!(n = get_name(so->proplist, "source-output")))
741 continue;
743 if (!pa_streq(name, n)) {
744 pa_xfree(n);
745 continue;
747 pa_xfree(n);
749 if (u->restore_device &&
750 e->device_valid &&
751 (s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SOURCE))) {
753 pa_log_info("Restoring device for stream %s.", name);
754 pa_source_output_move_to(so, s, TRUE);
759 #if 0
760 static void dump_database(struct userdata *u) {
761 pa_datum key;
762 pa_bool_t done;
764 done = !pa_database_first(u->database, &key, NULL);
766 while (!done) {
767 pa_datum next_key;
768 struct entry *e;
769 char *name;
771 done = !pa_database_next(u->database, &key, &next_key, NULL);
773 name = pa_xstrndup(key.data, key.size);
774 pa_datum_free(&key);
776 if ((e = read_entry(u, name))) {
777 char t[256];
778 pa_log("name=%s", name);
779 pa_log("device=%s %s", e->device, pa_yes_no(e->device_valid));
780 pa_log("channel_map=%s", pa_channel_map_snprint(t, sizeof(t), &e->channel_map));
781 pa_log("volume=%s %s", pa_cvolume_snprint(t, sizeof(t), &e->volume), pa_yes_no(e->volume_valid));
782 pa_log("mute=%s %s", pa_yes_no(e->muted), pa_yes_no(e->volume_valid));
783 pa_xfree(e);
786 pa_xfree(name);
788 key = next_key;
791 #endif
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;
798 pa_assert(p);
799 pa_assert(m);
800 pa_assert(c);
801 pa_assert(t);
803 u = m->userdata;
805 if (pa_tagstruct_getu32(t, &command) < 0)
806 goto fail;
808 reply = pa_tagstruct_new(NULL, 0);
809 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
810 pa_tagstruct_putu32(reply, tag);
812 switch (command) {
813 case SUBCOMMAND_TEST: {
814 if (!pa_tagstruct_eof(t))
815 goto fail;
817 pa_tagstruct_putu32(reply, EXT_VERSION);
818 break;
821 case SUBCOMMAND_READ: {
822 pa_datum key;
823 pa_bool_t done;
825 if (!pa_tagstruct_eof(t))
826 goto fail;
828 done = !pa_database_first(u->database, &key, NULL);
830 while (!done) {
831 pa_datum next_key;
832 struct entry *e;
833 char *name;
835 done = !pa_database_next(u->database, &key, &next_key, NULL);
837 name = pa_xstrndup(key.data, key.size);
838 pa_datum_free(&key);
840 if ((e = read_entry(u, name))) {
841 pa_cvolume r;
842 pa_channel_map cm;
844 pa_tagstruct_puts(reply, name);
845 pa_tagstruct_put_channel_map(reply, e->volume_valid ? &e->channel_map : pa_channel_map_init(&cm));
846 pa_tagstruct_put_cvolume(reply, e->volume_valid ? &e->volume : pa_cvolume_init(&r));
847 pa_tagstruct_puts(reply, e->device_valid ? e->device : NULL);
848 pa_tagstruct_put_boolean(reply, e->muted_valid ? e->muted : FALSE);
850 pa_xfree(e);
853 pa_xfree(name);
855 key = next_key;
858 break;
861 case SUBCOMMAND_WRITE: {
862 uint32_t mode;
863 pa_bool_t apply_immediately = FALSE;
865 if (pa_tagstruct_getu32(t, &mode) < 0 ||
866 pa_tagstruct_get_boolean(t, &apply_immediately) < 0)
867 goto fail;
869 if (mode != PA_UPDATE_MERGE &&
870 mode != PA_UPDATE_REPLACE &&
871 mode != PA_UPDATE_SET)
872 goto fail;
874 if (mode == PA_UPDATE_SET)
875 pa_database_clear(u->database);
877 while (!pa_tagstruct_eof(t)) {
878 const char *name, *device;
879 pa_bool_t muted;
880 struct entry entry;
881 pa_datum key, data;
883 pa_zero(entry);
884 entry.version = ENTRY_VERSION;
886 if (pa_tagstruct_gets(t, &name) < 0 ||
887 pa_tagstruct_get_channel_map(t, &entry.channel_map) ||
888 pa_tagstruct_get_cvolume(t, &entry.volume) < 0 ||
889 pa_tagstruct_gets(t, &device) < 0 ||
890 pa_tagstruct_get_boolean(t, &muted) < 0)
891 goto fail;
893 if (!name || !*name)
894 goto fail;
896 entry.volume_valid = entry.volume.channels > 0;
898 if (entry.volume_valid)
899 if (!pa_cvolume_compatible_with_channel_map(&entry.volume, &entry.channel_map))
900 goto fail;
902 entry.muted = muted;
903 entry.muted_valid = TRUE;
905 if (device)
906 pa_strlcpy(entry.device, device, sizeof(entry.device));
907 entry.device_valid = !!entry.device[0];
909 if (entry.device_valid &&
910 !pa_namereg_is_valid_name(entry.device))
911 goto fail;
913 key.data = (char*) name;
914 key.size = strlen(name);
916 data.data = &entry;
917 data.size = sizeof(entry);
919 if (pa_database_set(u->database, &key, &data, mode == PA_UPDATE_REPLACE) == 0)
920 if (apply_immediately)
921 apply_entry(u, name, &entry);
924 trigger_save(u);
926 break;
929 case SUBCOMMAND_DELETE:
931 while (!pa_tagstruct_eof(t)) {
932 const char *name;
933 pa_datum key;
935 if (pa_tagstruct_gets(t, &name) < 0)
936 goto fail;
938 key.data = (char*) name;
939 key.size = strlen(name);
941 pa_database_unset(u->database, &key);
944 trigger_save(u);
946 break;
948 case SUBCOMMAND_SUBSCRIBE: {
950 pa_bool_t enabled;
952 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
953 !pa_tagstruct_eof(t))
954 goto fail;
956 if (enabled)
957 pa_idxset_put(u->subscribed, c, NULL);
958 else
959 pa_idxset_remove_by_data(u->subscribed, c, NULL);
961 break;
964 default:
965 goto fail;
968 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
969 return 0;
971 fail:
973 if (reply)
974 pa_tagstruct_free(reply);
976 return -1;
979 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
980 pa_assert(p);
981 pa_assert(c);
982 pa_assert(u);
984 pa_idxset_remove_by_data(u->subscribed, c, NULL);
985 return PA_HOOK_OK;
988 int pa__init(pa_module*m) {
989 pa_modargs *ma = NULL;
990 struct userdata *u;
991 char *fname;
992 pa_sink_input *si;
993 pa_source_output *so;
994 uint32_t idx;
995 pa_bool_t restore_device = TRUE, restore_volume = TRUE, restore_muted = TRUE, on_hotplug = TRUE, on_rescue = TRUE;
997 pa_assert(m);
999 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1000 pa_log("Failed to parse module arguments");
1001 goto fail;
1004 if (pa_modargs_get_value_boolean(ma, "restore_device", &restore_device) < 0 ||
1005 pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
1006 pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
1007 pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
1008 pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
1009 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
1010 goto fail;
1013 if (!restore_muted && !restore_volume && !restore_device)
1014 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
1016 m->userdata = u = pa_xnew0(struct userdata, 1);
1017 u->core = m->core;
1018 u->module = m;
1019 u->restore_device = restore_device;
1020 u->restore_volume = restore_volume;
1021 u->restore_muted = restore_muted;
1022 u->on_hotplug = on_hotplug;
1023 u->on_rescue = on_rescue;
1024 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1026 u->protocol = pa_native_protocol_get(m->core);
1027 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1029 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);
1031 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
1033 if (restore_device) {
1034 /* A little bit earlier than module-intended-roles ... */
1035 u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_hook_callback, u);
1036 u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_new_hook_callback, u);
1039 if (restore_device && on_hotplug) {
1040 /* A little bit earlier than module-intended-roles ... */
1041 u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_put_hook_callback, u);
1042 u->source_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE, (pa_hook_cb_t) source_put_hook_callback, u);
1045 if (restore_device && on_rescue) {
1046 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
1047 u->sink_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_unlink_hook_callback, u);
1048 u->source_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_unlink_hook_callback, u);
1051 if (restore_volume || restore_muted)
1052 u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_fixate_hook_callback, u);
1054 if (!(fname = pa_state_path("stream-volumes", TRUE)))
1055 goto fail;
1057 if (!(u->database = pa_database_open(fname, TRUE))) {
1058 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
1059 pa_xfree(fname);
1060 goto fail;
1063 pa_log_info("Sucessfully opened database file '%s'.", fname);
1064 pa_xfree(fname);
1066 PA_IDXSET_FOREACH(si, m->core->sink_inputs, idx)
1067 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, si->index, u);
1069 PA_IDXSET_FOREACH(so, m->core->source_outputs, idx)
1070 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, so->index, u);
1072 pa_modargs_free(ma);
1073 return 0;
1075 fail:
1076 pa__done(m);
1078 if (ma)
1079 pa_modargs_free(ma);
1081 return -1;
1084 void pa__done(pa_module*m) {
1085 struct userdata* u;
1087 pa_assert(m);
1089 if (!(u = m->userdata))
1090 return;
1092 if (u->subscription)
1093 pa_subscription_free(u->subscription);
1095 if (u->sink_input_new_hook_slot)
1096 pa_hook_slot_free(u->sink_input_new_hook_slot);
1097 if (u->sink_input_fixate_hook_slot)
1098 pa_hook_slot_free(u->sink_input_fixate_hook_slot);
1099 if (u->source_output_new_hook_slot)
1100 pa_hook_slot_free(u->source_output_new_hook_slot);
1102 if (u->sink_put_hook_slot)
1103 pa_hook_slot_free(u->sink_put_hook_slot);
1104 if (u->source_put_hook_slot)
1105 pa_hook_slot_free(u->source_put_hook_slot);
1107 if (u->sink_unlink_hook_slot)
1108 pa_hook_slot_free(u->sink_unlink_hook_slot);
1109 if (u->source_unlink_hook_slot)
1110 pa_hook_slot_free(u->source_unlink_hook_slot);
1112 if (u->connection_unlink_hook_slot)
1113 pa_hook_slot_free(u->connection_unlink_hook_slot);
1115 if (u->save_time_event)
1116 u->core->mainloop->time_free(u->save_time_event);
1118 if (u->database)
1119 pa_database_close(u->database);
1121 if (u->protocol) {
1122 pa_native_protocol_remove_ext(u->protocol, m);
1123 pa_native_protocol_unref(u->protocol);
1126 if (u->subscribed)
1127 pa_idxset_free(u->subscribed, NULL, NULL);
1129 pa_xfree(u);