2 This file is part of PulseAudio.
4 Copyright 2006-2008 Lennart Poettering
5 Copyright 2011 Colin Guthrie
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.
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.
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
30 #include <sys/types.h>
34 #include <pulse/gccmacro.h>
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/rtclock.h>
39 #include <pulse/format.h>
40 #include <pulse/internal.h>
42 #include <pulsecore/core-error.h>
43 #include <pulsecore/module.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/modargs.h>
46 #include <pulsecore/log.h>
47 #include <pulsecore/core-subscribe.h>
48 #include <pulsecore/sink.h>
49 #include <pulsecore/source.h>
50 #include <pulsecore/namereg.h>
51 #include <pulsecore/protocol-native.h>
52 #include <pulsecore/pstream.h>
53 #include <pulsecore/pstream-util.h>
54 #include <pulsecore/database.h>
55 #include <pulsecore/tagstruct.h>
57 #include "module-device-restore-symdef.h"
59 PA_MODULE_AUTHOR("Lennart Poettering");
60 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute state of devices");
61 PA_MODULE_VERSION(PACKAGE_VERSION);
62 PA_MODULE_LOAD_ONCE(TRUE);
64 "restore_port=<Save/restore port?> "
65 "restore_volume=<Save/restore volumes?> "
66 "restore_muted=<Save/restore muted states?> "
67 "restore_formats=<Save/restore saved formats?>");
69 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
71 static const char* const valid_modargs[] = {
82 pa_subscription *subscription;
85 *sink_fixate_hook_slot,
88 *source_new_hook_slot,
89 *source_fixate_hook_slot,
90 *source_port_hook_slot,
91 *connection_unlink_hook_slot;
92 pa_time_event *save_time_event;
93 pa_database *database;
95 pa_native_protocol *protocol;
96 pa_idxset *subscribed;
98 pa_bool_t restore_volume:1;
99 pa_bool_t restore_muted:1;
100 pa_bool_t restore_port:1;
101 pa_bool_t restore_formats:1;
104 /* Protocol extension commands */
107 SUBCOMMAND_SUBSCRIBE,
109 SUBCOMMAND_READ_FORMATS_ALL,
110 SUBCOMMAND_READ_FORMATS,
111 SUBCOMMAND_SAVE_FORMATS
115 #define ENTRY_VERSION 1
119 pa_bool_t port_valid;
123 #define PERPORTENTRY_VERSION 1
125 struct perportentry {
127 pa_bool_t muted_valid, volume_valid;
129 pa_channel_map channel_map;
134 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
135 struct userdata *u = userdata;
141 pa_assert(e == u->save_time_event);
142 u->core->mainloop->time_free(u->save_time_event);
143 u->save_time_event = NULL;
145 pa_database_sync(u->database);
146 pa_log_info("Synced.");
149 static void trigger_save(struct userdata *u, pa_device_type_t type, uint32_t sink_idx) {
150 pa_native_connection *c;
153 if (sink_idx != PA_INVALID_INDEX) {
154 PA_IDXSET_FOREACH(c, u->subscribed, idx) {
157 t = pa_tagstruct_new(NULL, 0);
158 pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
159 pa_tagstruct_putu32(t, 0);
160 pa_tagstruct_putu32(t, u->module->index);
161 pa_tagstruct_puts(t, u->module->name);
162 pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
163 pa_tagstruct_putu32(t, type);
164 pa_tagstruct_putu32(t, sink_idx);
166 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
170 if (u->save_time_event)
173 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
177 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
178 /* Some forward declarations */
179 static pa_bool_t legacy_entry_read(struct userdata *u, pa_datum *data, struct entry **entry, struct perportentry **perportentry);
180 static struct perportentry* perportentry_read(struct userdata *u, const char *basekeyname, const char *port);
181 static pa_bool_t perportentry_write(struct userdata *u, const char *basekeyname, const char *port, const struct perportentry *e);
182 static void perportentry_free(struct perportentry* e);
185 static struct entry* entry_new(void) {
186 struct entry *r = pa_xnew0(struct entry, 1);
187 r->version = ENTRY_VERSION;
191 static void entry_free(struct entry* e) {
198 static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e) {
207 t = pa_tagstruct_new(NULL, 0);
208 pa_tagstruct_putu8(t, e->version);
209 pa_tagstruct_put_boolean(t, e->port_valid);
210 pa_tagstruct_puts(t, e->port);
212 key.data = (char *) name;
213 key.size = strlen(name);
215 data.data = (void*)pa_tagstruct_data(t, &data.size);
217 r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
219 pa_tagstruct_free(t);
224 static struct entry* entry_read(struct userdata *u, const char *name) {
226 struct entry *e = NULL;
227 pa_tagstruct *t = NULL;
233 key.data = (char*) name;
234 key.size = strlen(name);
238 if (!pa_database_get(u->database, &key, &data))
241 t = pa_tagstruct_new(data.data, data.size);
244 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
245 e->version > ENTRY_VERSION ||
246 pa_tagstruct_get_boolean(t, &e->port_valid) < 0 ||
247 pa_tagstruct_gets(t, &port) < 0) {
252 if (!pa_tagstruct_eof(t))
255 e->port = pa_xstrdup(port);
257 pa_tagstruct_free(t);
258 pa_datum_free(&data);
264 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
269 pa_tagstruct_free(t);
271 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
273 struct perportentry *ppe;
274 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name);
275 if (legacy_entry_read(u, &data, &e, &ppe)) {
276 pa_bool_t written = FALSE;
278 pa_log_debug("Success. Saving new format for key: %s", name);
279 written = entry_write(u, name, e);
281 /* Now convert the legacy entry into per-port entries */
282 if (0 == strncmp("sink:", name, 5)) {
285 if ((sink = pa_namereg_get(u->core, name+5, PA_NAMEREG_SINK))) {
286 /* Write a "null" port entry. The read code will automatically try this
287 * if it cannot find a specific port-named entry. */
288 written = perportentry_write(u, name, NULL, ppe) || written;
290 } else if (0 == strncmp("source:", name, 7)) {
293 if ((source = pa_namereg_get(u->core, name+7, PA_NAMEREG_SOURCE))) {
294 /* Write a "null" port entry. The read code will automatically try this
295 * if it cannot find a specific port-named entry. */
296 written = perportentry_write(u, name, NULL, ppe) || written;
299 perportentry_free(ppe);
302 /* NB The device type doesn't matter when we pass in an invalid index. */
303 trigger_save(u, PA_DEVICE_TYPE_SINK, PA_INVALID_INDEX);
305 pa_datum_free(&data);
308 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name);
312 pa_datum_free(&data);
316 static struct entry* entry_copy(const struct entry *e) {
321 r->version = e->version;
322 r->port_valid = e->port_valid;
323 r->port = pa_xstrdup(e->port);
328 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
332 if (a->port_valid != b->port_valid ||
333 (a->port_valid && !pa_streq(a->port, b->port)))
339 static struct perportentry* perportentry_new(pa_bool_t add_pcm_format) {
340 struct perportentry *r = pa_xnew0(struct perportentry, 1);
341 r->version = PERPORTENTRY_VERSION;
342 r->formats = pa_idxset_new(NULL, NULL);
343 if (add_pcm_format) {
344 pa_format_info *f = pa_format_info_new();
345 f->encoding = PA_ENCODING_PCM;
346 pa_idxset_put(r->formats, f, NULL);
351 static void perportentry_free(struct perportentry* e) {
354 pa_idxset_free(e->formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
358 static pa_bool_t perportentry_write(struct userdata *u, const char *basekeyname, const char *port, const struct perportentry *e) {
368 pa_assert(basekeyname);
371 name = pa_sprintf_malloc("%s:%s", basekeyname, (port ? port : "null"));
373 n_formats = pa_idxset_size(e->formats);
374 pa_assert(n_formats > 0);
376 t = pa_tagstruct_new(NULL, 0);
377 pa_tagstruct_putu8(t, e->version);
378 pa_tagstruct_put_boolean(t, e->volume_valid);
379 pa_tagstruct_put_channel_map(t, &e->channel_map);
380 pa_tagstruct_put_cvolume(t, &e->volume);
381 pa_tagstruct_put_boolean(t, e->muted_valid);
382 pa_tagstruct_put_boolean(t, e->muted);
383 pa_tagstruct_putu8(t, n_formats);
385 PA_IDXSET_FOREACH(f, e->formats, i) {
386 pa_tagstruct_put_format_info(t, f);
389 key.data = (char *) name;
390 key.size = strlen(name);
392 data.data = (void*)pa_tagstruct_data(t, &data.size);
394 r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
396 pa_tagstruct_free(t);
402 static struct perportentry* perportentry_read(struct userdata *u, const char *basekeyname, const char *port) {
404 struct perportentry *e = NULL;
405 pa_tagstruct *t = NULL;
406 uint8_t i, n_formats;
410 pa_assert(basekeyname);
412 name = pa_sprintf_malloc("%s:%s", basekeyname, (port ? port : "null"));
415 key.size = strlen(name);
419 if (!pa_database_get(u->database, &key, &data))
422 t = pa_tagstruct_new(data.data, data.size);
423 e = perportentry_new(FALSE);
425 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
426 e->version > PERPORTENTRY_VERSION ||
427 pa_tagstruct_get_boolean(t, &e->volume_valid) < 0 ||
428 pa_tagstruct_get_channel_map(t, &e->channel_map) < 0 ||
429 pa_tagstruct_get_cvolume(t, &e->volume) < 0 ||
430 pa_tagstruct_get_boolean(t, &e->muted_valid) < 0 ||
431 pa_tagstruct_get_boolean(t, &e->muted) < 0 ||
432 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
437 for (i = 0; i < n_formats; ++i) {
438 pa_format_info *f = pa_format_info_new();
439 if (pa_tagstruct_get_format_info(t, f) < 0) {
440 pa_format_info_free(f);
443 pa_idxset_put(e->formats, f, NULL);
446 if (!pa_tagstruct_eof(t))
449 if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
450 pa_log_warn("Invalid channel map stored in database for device %s", name);
454 if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
455 pa_log_warn("Volume and channel map don't match in database entry for device %s", name);
459 pa_tagstruct_free(t);
460 pa_datum_free(&data);
468 perportentry_free(e);
470 pa_tagstruct_free(t);
472 pa_datum_free(&data);
474 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
475 /* Try again with a null port. This is used when dealing with migration from older versions */
478 return perportentry_read(u, basekeyname, NULL);
482 pa_log_debug("Database contains invalid data for key: %s", name);
489 static struct perportentry* perportentry_copy(const struct perportentry *e) {
490 struct perportentry* r;
495 r = perportentry_new(FALSE);
496 r->version = e->version;
497 r->muted_valid = e->muted_valid;
498 r->volume_valid = e->volume_valid;
500 r->channel_map = e->channel_map;
501 r->volume = e->volume;
503 PA_IDXSET_FOREACH(f, e->formats, idx) {
504 pa_idxset_put(r->formats, pa_format_info_copy(f), NULL);
509 static pa_bool_t perportentries_equal(const struct perportentry *a, const struct perportentry *b) {
514 if (a->muted_valid != b->muted_valid ||
515 (a->muted_valid && (a->muted != b->muted)))
519 if (a->volume_valid != b->volume_valid ||
520 (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
523 if (pa_idxset_size(a->formats) != pa_idxset_size(b->formats))
526 /** TODO: Compare a bit better */
531 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
533 #define LEGACY_ENTRY_VERSION 2
534 static pa_bool_t legacy_entry_read(struct userdata *u, pa_datum *data, struct entry **entry, struct perportentry **perportentry) {
535 struct legacy_entry {
537 pa_bool_t muted_valid:1, volume_valid:1, port_valid:1;
539 pa_channel_map channel_map;
541 char port[PA_NAME_MAX];
543 struct legacy_entry *le;
548 pa_assert(perportentry);
550 if (data->size != sizeof(struct legacy_entry)) {
551 pa_log_debug("Size does not match.");
555 le = (struct legacy_entry*)data->data;
557 if (le->version != LEGACY_ENTRY_VERSION) {
558 pa_log_debug("Version mismatch.");
562 if (!memchr(le->port, 0, sizeof(le->port))) {
563 pa_log_warn("Port has missing NUL byte.");
567 if (le->volume_valid && !pa_channel_map_valid(&le->channel_map)) {
568 pa_log_warn("Invalid channel map.");
572 if (le->volume_valid && (!pa_cvolume_valid(&le->volume) || !pa_cvolume_compatible_with_channel_map(&le->volume, &le->channel_map))) {
573 pa_log_warn("Volume and channel map don't match.");
577 *entry = entry_new();
578 (*entry)->port_valid = le->port_valid;
579 (*entry)->port = pa_xstrdup(le->port);
581 *perportentry = perportentry_new(TRUE);
582 (*perportentry)->muted_valid = le->muted_valid;
583 (*perportentry)->volume_valid = le->volume_valid;
584 (*perportentry)->muted = le->muted;
585 (*perportentry)->channel_map = le->channel_map;
586 (*perportentry)->volume = le->volume;
592 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
593 struct userdata *u = userdata;
594 struct entry *e, *olde;
595 struct perportentry *ppe, *oldppe;
597 const char *port = NULL;
598 pa_device_type_t type;
599 pa_bool_t written = FALSE;
604 if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
605 t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
606 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
607 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
610 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
613 if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
616 type = PA_DEVICE_TYPE_SINK;
617 name = pa_sprintf_malloc("sink:%s", sink->name);
618 if (sink->active_port)
619 port = sink->active_port->name;
621 if ((olde = entry_read(u, name)))
622 e = entry_copy(olde);
626 if (sink->save_port) {
628 e->port = pa_xstrdup(port ? port : "");
629 e->port_valid = TRUE;
632 if ((oldppe = perportentry_read(u, name, port)))
633 ppe = perportentry_copy(oldppe);
635 ppe = perportentry_new(TRUE);
637 if (sink->save_volume) {
638 ppe->channel_map = sink->channel_map;
639 ppe->volume = *pa_sink_get_volume(sink, FALSE);
640 ppe->volume_valid = TRUE;
643 if (sink->save_muted) {
644 ppe->muted = pa_sink_get_mute(sink, FALSE);
645 ppe->muted_valid = TRUE;
650 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
652 if (!(source = pa_idxset_get_by_index(c->sources, idx)))
655 type = PA_DEVICE_TYPE_SOURCE;
656 name = pa_sprintf_malloc("source:%s", source->name);
657 if (source->active_port)
658 port = source->active_port->name;
660 if ((olde = entry_read(u, name)))
661 e = entry_copy(olde);
665 if (source->save_port) {
667 e->port = pa_xstrdup(port ? port : "");
668 e->port_valid = TRUE;
671 if ((oldppe = perportentry_read(u, name, port)))
672 ppe = perportentry_copy(oldppe);
674 ppe = perportentry_new(TRUE);
676 if (source->save_volume) {
677 ppe->channel_map = source->channel_map;
678 ppe->volume = *pa_source_get_volume(source, FALSE);
679 ppe->volume_valid = TRUE;
682 if (source->save_muted) {
683 ppe->muted = pa_source_get_mute(source, FALSE);
684 ppe->muted_valid = TRUE;
693 if (entries_equal(olde, e)) {
702 pa_log_info("Storing port for device %s.", name);
704 written = entry_write(u, name, e);
714 if (perportentries_equal(oldppe, ppe)) {
715 perportentry_free(oldppe);
716 perportentry_free(ppe);
719 perportentry_free(oldppe);
723 pa_log_info("Storing volume/mute for device+port %s:%s.", name, (port ? port : "null"));
725 written = perportentry_write(u, name, port, ppe) || written;
727 perportentry_free(ppe);
732 trigger_save(u, type, idx);
735 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
742 pa_assert(u->restore_port);
744 name = pa_sprintf_malloc("sink:%s", new_data->name);
746 if ((e = entry_read(u, name))) {
749 if (!new_data->active_port) {
750 pa_log_info("Restoring port for sink %s.", name);
751 pa_sink_new_data_set_port(new_data, e->port);
752 new_data->save_port = TRUE;
754 pa_log_debug("Not restoring port for sink %s, because already set.", name);
765 static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
767 struct perportentry *e;
772 pa_assert(u->restore_volume || u->restore_muted);
774 name = pa_sprintf_malloc("sink:%s", new_data->name);
776 if ((e = perportentry_read(u, name, new_data->active_port))) {
778 if (u->restore_volume && e->volume_valid) {
780 if (!new_data->volume_is_set) {
782 char buf[PA_CVOLUME_SNPRINT_MAX];
784 pa_log_info("Restoring volume for sink %s.", new_data->name);
786 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
787 pa_sink_new_data_set_volume(new_data, &v);
788 pa_log_info("Restored volume: %s", pa_cvolume_snprint(buf, PA_CVOLUME_SNPRINT_MAX, &new_data->volume));
790 new_data->save_volume = TRUE;
792 pa_log_debug("Not restoring volume for sink %s, because already set.", new_data->name);
795 if (u->restore_muted && e->muted_valid) {
797 if (!new_data->muted_is_set) {
798 pa_log_info("Restoring mute state for sink %s.", new_data->name);
799 pa_sink_new_data_set_muted(new_data, e->muted);
800 new_data->save_muted = TRUE;
802 pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
805 perportentry_free(e);
813 static pa_hook_result_t sink_port_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
815 struct perportentry *e;
820 pa_assert(u->restore_volume || u->restore_muted);
822 name = pa_sprintf_malloc("sink:%s", sink->name);
824 if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
826 if (u->restore_volume && e->volume_valid) {
828 char buf[PA_CVOLUME_SNPRINT_MAX];
830 pa_log_info("Restoring volume for sink %s.", sink->name);
832 pa_cvolume_remap(&v, &e->channel_map, &sink->channel_map);
833 pa_sink_set_volume(sink, &v, TRUE, FALSE);
834 pa_log_info("Restored volume: %s", pa_cvolume_snprint(buf, PA_CVOLUME_SNPRINT_MAX, &sink->reference_volume));
836 sink->save_volume = TRUE;
839 if (u->restore_muted && e->muted_valid) {
841 pa_log_info("Restoring mute state for sink %s.", sink->name);
842 pa_sink_set_mute(sink, e->muted, FALSE);
843 sink->save_muted = TRUE;
846 perportentry_free(e);
854 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
856 struct perportentry *e;
861 pa_assert(u->restore_formats);
863 name = pa_sprintf_malloc("sink:%s", sink->name);
865 if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
867 if (!pa_sink_set_formats(sink, e->formats))
868 pa_log_debug("Could not set format on sink %s", sink->name);
870 perportentry_free(e);
878 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
885 pa_assert(u->restore_port);
887 name = pa_sprintf_malloc("source:%s", new_data->name);
889 if ((e = entry_read(u, name))) {
892 if (!new_data->active_port) {
893 pa_log_info("Restoring port for source %s.", name);
894 pa_source_new_data_set_port(new_data, e->port);
895 new_data->save_port = TRUE;
897 pa_log_debug("Not restoring port for source %s, because already set.", name);
908 static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
910 struct perportentry *e;
915 pa_assert(u->restore_volume || u->restore_muted);
917 name = pa_sprintf_malloc("source:%s", new_data->name);
919 if ((e = perportentry_read(u, name, new_data->active_port))) {
921 if (u->restore_volume && e->volume_valid) {
923 if (!new_data->volume_is_set) {
925 char buf[PA_CVOLUME_SNPRINT_MAX];
927 pa_log_info("Restoring volume for source %s.", new_data->name);
929 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
930 pa_source_new_data_set_volume(new_data, &v);
931 pa_log_info("Restored volume: %s", pa_cvolume_snprint(buf, PA_CVOLUME_SNPRINT_MAX, &new_data->volume));
933 new_data->save_volume = TRUE;
935 pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name);
938 if (u->restore_muted && e->muted_valid) {
940 if (!new_data->muted_is_set) {
941 pa_log_info("Restoring mute state for source %s.", new_data->name);
942 pa_source_new_data_set_muted(new_data, e->muted);
943 new_data->save_muted = TRUE;
945 pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
948 perportentry_free(e);
956 static pa_hook_result_t source_port_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
958 struct perportentry *e;
963 pa_assert(u->restore_volume || u->restore_muted);
965 name = pa_sprintf_malloc("source:%s", source->name);
967 if ((e = perportentry_read(u, name, (source->active_port ? source->active_port->name : NULL)))) {
969 if (u->restore_volume && e->volume_valid) {
971 char buf[PA_CVOLUME_SNPRINT_MAX];
973 pa_log_info("Restoring volume for source %s.", source->name);
975 pa_cvolume_remap(&v, &e->channel_map, &source->channel_map);
976 pa_source_set_volume(source, &v, TRUE, FALSE);
977 pa_log_info("Restored volume: %s", pa_cvolume_snprint(buf, PA_CVOLUME_SNPRINT_MAX, &source->reference_volume));
979 source->save_volume = TRUE;
982 if (u->restore_muted && e->muted_valid) {
984 pa_log_info("Restoring mute state for source %s.", source->name);
985 pa_source_set_mute(source, e->muted, FALSE);
986 source->save_muted = TRUE;
989 perportentry_free(e);
997 #define EXT_VERSION 1
999 static void read_sink_format_reply(struct userdata *u, pa_tagstruct *reply, pa_sink *sink) {
1000 struct perportentry *e;
1007 pa_tagstruct_putu32(reply, PA_DEVICE_TYPE_SINK);
1008 pa_tagstruct_putu32(reply, sink->index);
1010 /* Read or create an entry */
1011 name = pa_sprintf_malloc("sink:%s", sink->name);
1012 if (!(e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
1013 /* Fake a reply with PCM encoding supported */
1014 pa_format_info *f = pa_format_info_new();
1016 pa_tagstruct_putu8(reply, 1);
1017 f->encoding = PA_ENCODING_PCM;
1018 pa_tagstruct_put_format_info(reply, f);
1020 pa_format_info_free(f);
1025 /* Write all the formats from the entry to the reply */
1026 pa_tagstruct_putu8(reply, pa_idxset_size(e->formats));
1027 PA_IDXSET_FOREACH(f, e->formats, idx) {
1028 pa_tagstruct_put_format_info(reply, f);
1034 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
1037 pa_tagstruct *reply = NULL;
1046 if (pa_tagstruct_getu32(t, &command) < 0)
1049 reply = pa_tagstruct_new(NULL, 0);
1050 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1051 pa_tagstruct_putu32(reply, tag);
1054 case SUBCOMMAND_TEST: {
1055 if (!pa_tagstruct_eof(t))
1058 pa_tagstruct_putu32(reply, EXT_VERSION);
1062 case SUBCOMMAND_SUBSCRIBE: {
1066 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1067 !pa_tagstruct_eof(t))
1071 pa_idxset_put(u->subscribed, c, NULL);
1073 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1078 case SUBCOMMAND_READ_FORMATS_ALL: {
1082 if (!pa_tagstruct_eof(t))
1085 PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
1086 read_sink_format_reply(u, reply, sink);
1091 case SUBCOMMAND_READ_FORMATS: {
1092 pa_device_type_t type;
1093 uint32_t sink_index;
1098 /* Get the sink index and the number of formats from the tagstruct */
1099 if (pa_tagstruct_getu32(t, &type) < 0 ||
1100 pa_tagstruct_getu32(t, &sink_index) < 0)
1103 if (type != PA_DEVICE_TYPE_SINK) {
1104 pa_log("Device format reading is only supported on sinks");
1108 if (!pa_tagstruct_eof(t))
1111 /* Now find our sink */
1112 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
1115 read_sink_format_reply(u, reply, sink);
1120 case SUBCOMMAND_SAVE_FORMATS: {
1122 struct perportentry *e;
1123 pa_device_type_t type;
1124 uint32_t sink_index;
1127 uint8_t i, n_formats;
1129 /* Get the sink index and the number of formats from the tagstruct */
1130 if (pa_tagstruct_getu32(t, &type) < 0 ||
1131 pa_tagstruct_getu32(t, &sink_index) < 0 ||
1132 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
1137 if (type != PA_DEVICE_TYPE_SINK) {
1138 pa_log("Device format saving is only supported on sinks");
1142 /* Now find our sink */
1143 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index))) {
1144 pa_log("Could not find sink #%d", sink_index);
1148 /* Read or create an entry */
1149 name = pa_sprintf_malloc("sink:%s", sink->name);
1150 if (!(e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL))))
1151 e = perportentry_new(FALSE);
1153 /* Clean out any saved formats */
1154 pa_idxset_free(e->formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
1155 e->formats = pa_idxset_new(NULL, NULL);
1158 /* Read all the formats from our tagstruct */
1159 for (i = 0; i < n_formats; ++i) {
1160 pa_format_info *f = pa_format_info_new();
1161 if (pa_tagstruct_get_format_info(t, f) < 0) {
1162 pa_format_info_free(f);
1166 pa_idxset_put(e->formats, f, NULL);
1169 if (!pa_tagstruct_eof(t)) {
1170 perportentry_free(e);
1175 if (pa_sink_set_formats(sink, e->formats) && perportentry_write(u, name, (sink->active_port ? sink->active_port->name : NULL), e))
1176 trigger_save(u, type, sink_index);
1178 pa_log_warn("Could not save format info for sink %s", sink->name);
1181 perportentry_free(e);
1190 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1196 pa_tagstruct_free(reply);
1201 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
1206 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1210 int pa__init(pa_module*m) {
1211 pa_modargs *ma = NULL;
1217 pa_bool_t restore_volume = TRUE, restore_muted = TRUE, restore_port = TRUE, restore_formats = TRUE;
1221 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1222 pa_log("Failed to parse module arguments");
1226 if (pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
1227 pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
1228 pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0 ||
1229 pa_modargs_get_value_boolean(ma, "restore_formats", &restore_formats) < 0) {
1230 pa_log("restore_port, restore_volume, restore_muted and restore_formats expect boolean arguments");
1234 if (!restore_muted && !restore_volume && !restore_port && !restore_formats)
1235 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring port enabled!");
1237 m->userdata = u = pa_xnew0(struct userdata, 1);
1240 u->restore_volume = restore_volume;
1241 u->restore_muted = restore_muted;
1242 u->restore_port = restore_port;
1243 u->restore_formats = restore_formats;
1245 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1247 u->protocol = pa_native_protocol_get(m->core);
1248 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1250 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);
1252 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
1255 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);
1256 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);
1259 if (restore_muted || restore_volume) {
1260 u->sink_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_fixate_hook_callback, u);
1261 u->source_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_fixate_hook_callback, u);
1263 u->sink_port_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) sink_port_hook_callback, u);
1264 u->source_port_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) source_port_hook_callback, u);
1267 if (restore_formats)
1268 u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_put_hook_callback, u);
1270 if (!(fname = pa_state_path("device-volumes", TRUE)))
1273 if (!(u->database = pa_database_open(fname, TRUE))) {
1274 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
1279 pa_log_info("Successfully opened database file '%s'.", fname);
1282 PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
1283 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
1285 PA_IDXSET_FOREACH(source, m->core->sources, idx)
1286 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
1288 pa_modargs_free(ma);
1295 pa_modargs_free(ma);
1300 void pa__done(pa_module*m) {
1305 if (!(u = m->userdata))
1308 if (u->subscription)
1309 pa_subscription_free(u->subscription);
1311 if (u->sink_fixate_hook_slot)
1312 pa_hook_slot_free(u->sink_fixate_hook_slot);
1313 if (u->source_fixate_hook_slot)
1314 pa_hook_slot_free(u->source_fixate_hook_slot);
1315 if (u->sink_new_hook_slot)
1316 pa_hook_slot_free(u->sink_new_hook_slot);
1317 if (u->source_new_hook_slot)
1318 pa_hook_slot_free(u->source_new_hook_slot);
1319 if (u->sink_port_hook_slot)
1320 pa_hook_slot_free(u->sink_port_hook_slot);
1321 if (u->source_port_hook_slot)
1322 pa_hook_slot_free(u->source_port_hook_slot);
1323 if (u->sink_put_hook_slot)
1324 pa_hook_slot_free(u->sink_put_hook_slot);
1326 if (u->connection_unlink_hook_slot)
1327 pa_hook_slot_free(u->connection_unlink_hook_slot);
1329 if (u->save_time_event)
1330 u->core->mainloop->time_free(u->save_time_event);
1333 pa_database_close(u->database);
1336 pa_native_protocol_remove_ext(u->protocol, m);
1337 pa_native_protocol_unref(u->protocol);
1341 pa_idxset_free(u->subscribed, NULL, NULL);