default: esd is obsolete, hence don't load it anymore by default
[pulseaudio-mirror.git] / src / modules / module-device-restore.c
blob7d94ffa4bb4b882fb1aa18ea6c0d592335838883
1 /***
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
20 USA.
21 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
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>
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);
63 PA_MODULE_USAGE(
64 "restore_port=<Save/restore port?> "
65 "restore_volume=<Save/restore volumes?> "
66 "restore_muted=<Save/restore muted states?>");
68 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
70 static const char* const valid_modargs[] = {
71 "restore_volume",
72 "restore_muted",
73 "restore_port",
74 NULL
77 struct userdata {
78 pa_core *core;
79 pa_module *module;
80 pa_subscription *subscription;
81 pa_hook_slot
82 *sink_new_hook_slot,
83 *sink_fixate_hook_slot,
84 *source_new_hook_slot,
85 *source_fixate_hook_slot,
86 *connection_unlink_hook_slot;
87 pa_time_event *save_time_event;
88 pa_database *database;
90 pa_native_protocol *protocol;
91 pa_idxset *subscribed;
93 pa_bool_t restore_volume:1;
94 pa_bool_t restore_muted:1;
95 pa_bool_t restore_port:1;
98 /* Protocol extention commands */
99 enum {
100 SUBCOMMAND_TEST,
101 SUBCOMMAND_SUBSCRIBE,
102 SUBCOMMAND_EVENT,
103 SUBCOMMAND_READ_SINK_FORMATS_ALL,
104 SUBCOMMAND_READ_SINK_FORMATS,
105 SUBCOMMAND_SAVE_SINK_FORMATS
109 #define ENTRY_VERSION 1
111 struct entry {
112 uint8_t version;
113 pa_bool_t muted_valid, volume_valid, port_valid;
114 pa_bool_t muted;
115 pa_channel_map channel_map;
116 pa_cvolume volume;
117 char *port;
118 pa_idxset *formats;
121 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
122 struct userdata *u = userdata;
124 pa_assert(a);
125 pa_assert(e);
126 pa_assert(u);
128 pa_assert(e == u->save_time_event);
129 u->core->mainloop->time_free(u->save_time_event);
130 u->save_time_event = NULL;
132 pa_database_sync(u->database);
133 pa_log_info("Synced.");
136 static void trigger_save(struct userdata *u) {
137 if (u->save_time_event)
138 return;
140 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
143 static struct entry* entry_new(pa_bool_t add_pcm_format) {
144 struct entry *r = pa_xnew0(struct entry, 1);
145 r->version = ENTRY_VERSION;
146 r->formats = pa_idxset_new(NULL, NULL);
147 if (add_pcm_format) {
148 pa_format_info *f = pa_format_info_new();
149 f->encoding = PA_ENCODING_PCM;
150 pa_idxset_put(r->formats, f, NULL);
152 return r;
155 static void entry_free(struct entry* e) {
156 pa_assert(e);
158 pa_idxset_free(e->formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
159 pa_xfree(e->port);
160 pa_xfree(e);
163 static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e) {
164 pa_tagstruct *t;
165 pa_datum key, data;
166 pa_bool_t r;
167 uint32_t i;
168 pa_format_info *f;
169 uint8_t n_formats;
171 pa_assert(u);
172 pa_assert(name);
173 pa_assert(e);
175 n_formats = pa_idxset_size(e->formats);
176 pa_assert(n_formats > 0);
178 t = pa_tagstruct_new(NULL, 0);
179 pa_tagstruct_putu8(t, e->version);
180 pa_tagstruct_put_boolean(t, e->volume_valid);
181 pa_tagstruct_put_channel_map(t, &e->channel_map);
182 pa_tagstruct_put_cvolume(t, &e->volume);
183 pa_tagstruct_put_boolean(t, e->muted_valid);
184 pa_tagstruct_put_boolean(t, e->muted);
185 pa_tagstruct_put_boolean(t, e->port_valid);
186 pa_tagstruct_puts(t, e->port);
187 pa_tagstruct_putu8(t, n_formats);
189 PA_IDXSET_FOREACH(f, e->formats, i) {
190 pa_tagstruct_put_format_info(t, f);
193 key.data = (char *) name;
194 key.size = strlen(name);
196 data.data = (void*)pa_tagstruct_data(t, &data.size);
198 r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
200 pa_tagstruct_free(t);
202 return r;
205 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
207 #define LEGACY_ENTRY_VERSION 2
208 static struct entry* legacy_entry_read(struct userdata *u, pa_datum *data) {
209 struct legacy_entry {
210 uint8_t version;
211 pa_bool_t muted_valid:1, volume_valid:1, port_valid:1;
212 pa_bool_t muted:1;
213 pa_channel_map channel_map;
214 pa_cvolume volume;
215 char port[PA_NAME_MAX];
216 } PA_GCC_PACKED;
217 struct legacy_entry *le;
218 struct entry *e;
220 pa_assert(u);
221 pa_assert(data);
223 if (data->size != sizeof(struct legacy_entry)) {
224 pa_log_debug("Size does not match.");
225 return NULL;
228 le = (struct legacy_entry*)data->data;
230 if (le->version != LEGACY_ENTRY_VERSION) {
231 pa_log_debug("Version mismatch.");
232 return NULL;
235 if (!memchr(le->port, 0, sizeof(le->port))) {
236 pa_log_warn("Port has missing NUL byte.");
237 return NULL;
240 if (le->volume_valid && !pa_channel_map_valid(&le->channel_map)) {
241 pa_log_warn("Invalid channel map.");
242 return NULL;
245 if (le->volume_valid && (!pa_cvolume_valid(&le->volume) || !pa_cvolume_compatible_with_channel_map(&le->volume, &le->channel_map))) {
246 pa_log_warn("Volume and channel map don't match.");
247 return NULL;
250 e = entry_new(TRUE);
251 e->muted_valid = le->muted_valid;
252 e->volume_valid = le->volume_valid;
253 e->port_valid = le->port_valid;
254 e->muted = le->muted;
255 e->channel_map = le->channel_map;
256 e->volume = le->volume;
257 e->port = pa_xstrdup(le->port);
258 return e;
260 #endif
262 static struct entry* entry_read(struct userdata *u, const char *name) {
263 pa_datum key, data;
264 struct entry *e = NULL;
265 pa_tagstruct *t = NULL;
266 const char* port;
267 uint8_t i, n_formats;
269 pa_assert(u);
270 pa_assert(name);
272 key.data = (char*) name;
273 key.size = strlen(name);
275 pa_zero(data);
277 if (!pa_database_get(u->database, &key, &data))
278 goto fail;
280 t = pa_tagstruct_new(data.data, data.size);
281 e = entry_new(FALSE);
283 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
284 e->version > ENTRY_VERSION ||
285 pa_tagstruct_get_boolean(t, &e->volume_valid) < 0 ||
286 pa_tagstruct_get_channel_map(t, &e->channel_map) < 0 ||
287 pa_tagstruct_get_cvolume(t, &e->volume) < 0 ||
288 pa_tagstruct_get_boolean(t, &e->muted_valid) < 0 ||
289 pa_tagstruct_get_boolean(t, &e->muted) < 0 ||
290 pa_tagstruct_get_boolean(t, &e->port_valid) < 0 ||
291 pa_tagstruct_gets(t, &port) < 0 ||
292 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
294 goto fail;
297 e->port = pa_xstrdup(port);
299 for (i = 0; i < n_formats; ++i) {
300 pa_format_info *f = pa_format_info_new();
301 if (pa_tagstruct_get_format_info(t, f) < 0) {
302 pa_format_info_free(f);
303 goto fail;
305 pa_idxset_put(e->formats, f, NULL);
308 if (!pa_tagstruct_eof(t))
309 goto fail;
311 if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
312 pa_log_warn("Invalid channel map stored in database for device %s", name);
313 goto fail;
316 if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
317 pa_log_warn("Volume and channel map don't match in database entry for device %s", name);
318 goto fail;
321 pa_tagstruct_free(t);
322 pa_datum_free(&data);
324 return e;
326 fail:
328 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
330 if (e)
331 entry_free(e);
332 if (t)
333 pa_tagstruct_free(t);
335 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
336 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name);
337 if ((e = legacy_entry_read(u, &data))) {
338 pa_log_debug("Success. Saving new format for key: %s", name);
339 if (entry_write(u, name, e))
340 trigger_save(u);
341 pa_datum_free(&data);
342 return e;
343 } else
344 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name);
345 #endif
347 pa_datum_free(&data);
348 return NULL;
351 static struct entry* entry_copy(const struct entry *e) {
352 struct entry* r;
353 uint32_t idx;
354 pa_format_info *f;
356 pa_assert(e);
357 r = entry_new(FALSE);
358 r->version = e->version;
359 r->muted_valid = e->muted_valid;
360 r->volume_valid = e->volume_valid;
361 r->port_valid = e->port_valid;
362 r->muted = e->muted;
363 r->channel_map = e->channel_map;
364 r->volume = e->volume;
365 r->port = pa_xstrdup(e->port);
367 PA_IDXSET_FOREACH(f, e->formats, idx) {
368 pa_idxset_put(r->formats, pa_format_info_copy(f), NULL);
370 return r;
373 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
374 pa_cvolume t;
376 if (a->port_valid != b->port_valid ||
377 (a->port_valid && !pa_streq(a->port, b->port)))
378 return FALSE;
380 if (a->muted_valid != b->muted_valid ||
381 (a->muted_valid && (a->muted != b->muted)))
382 return FALSE;
384 t = b->volume;
385 if (a->volume_valid != b->volume_valid ||
386 (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
387 return FALSE;
389 if (pa_idxset_size(a->formats) != pa_idxset_size(b->formats))
390 return FALSE;
392 /** TODO: Compare a bit better */
394 return TRUE;
397 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
398 struct userdata *u = userdata;
399 struct entry *entry, *old;
400 char *name;
402 pa_assert(c);
403 pa_assert(u);
405 if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
406 t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
407 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
408 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
409 return;
411 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
412 pa_sink *sink;
414 if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
415 return;
417 name = pa_sprintf_malloc("sink:%s", sink->name);
419 if ((old = entry_read(u, name)))
420 entry = entry_copy(old);
421 else
422 entry = entry_new(TRUE);
424 if (sink->save_volume) {
425 entry->channel_map = sink->channel_map;
426 entry->volume = *pa_sink_get_volume(sink, FALSE);
427 entry->volume_valid = TRUE;
430 if (sink->save_muted) {
431 entry->muted = pa_sink_get_mute(sink, FALSE);
432 entry->muted_valid = TRUE;
435 if (sink->save_port) {
436 pa_xfree(entry->port);
437 entry->port = pa_xstrdup(sink->active_port ? sink->active_port->name : "");
438 entry->port_valid = TRUE;
441 } else {
442 pa_source *source;
444 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
446 if (!(source = pa_idxset_get_by_index(c->sources, idx)))
447 return;
449 name = pa_sprintf_malloc("source:%s", source->name);
451 if ((old = entry_read(u, name)))
452 entry = entry_copy(old);
453 else
454 entry = entry_new(TRUE);
456 if (source->save_volume) {
457 entry->channel_map = source->channel_map;
458 entry->volume = *pa_source_get_volume(source, FALSE);
459 entry->volume_valid = TRUE;
462 if (source->save_muted) {
463 entry->muted = pa_source_get_mute(source, FALSE);
464 entry->muted_valid = TRUE;
467 if (source->save_port) {
468 pa_xfree(entry->port);
469 entry->port = pa_xstrdup(source->active_port ? source->active_port->name : "");
470 entry->port_valid = TRUE;
474 pa_assert(entry);
476 if (old) {
478 if (entries_equal(old, entry)) {
479 entry_free(old);
480 entry_free(entry);
481 pa_xfree(name);
482 return;
485 entry_free(old);
488 pa_log_info("Storing volume/mute/port for device %s.", name);
490 if (entry_write(u, name, entry))
491 trigger_save(u);
493 entry_free(entry);
494 pa_xfree(name);
497 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
498 char *name;
499 struct entry *e;
501 pa_assert(c);
502 pa_assert(new_data);
503 pa_assert(u);
504 pa_assert(u->restore_port);
506 name = pa_sprintf_malloc("sink:%s", new_data->name);
508 if ((e = entry_read(u, name))) {
510 if (e->port_valid) {
511 if (!new_data->active_port) {
512 pa_log_info("Restoring port for sink %s.", name);
513 pa_sink_new_data_set_port(new_data, e->port);
514 new_data->save_port = TRUE;
515 } else
516 pa_log_debug("Not restoring port for sink %s, because already set.", name);
519 entry_free(e);
522 pa_xfree(name);
524 return PA_HOOK_OK;
527 static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
528 char *name;
529 struct entry *e;
531 pa_assert(c);
532 pa_assert(new_data);
533 pa_assert(u);
534 pa_assert(u->restore_volume || u->restore_muted);
536 name = pa_sprintf_malloc("sink:%s", new_data->name);
538 if ((e = entry_read(u, name))) {
540 if (u->restore_volume && e->volume_valid) {
542 if (!new_data->volume_is_set) {
543 pa_cvolume v;
545 pa_log_info("Restoring volume for sink %s.", new_data->name);
547 v = e->volume;
548 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
549 pa_sink_new_data_set_volume(new_data, &v);
551 new_data->save_volume = TRUE;
552 } else
553 pa_log_debug("Not restoring volume for sink %s, because already set.", new_data->name);
556 if (u->restore_muted && e->muted_valid) {
558 if (!new_data->muted_is_set) {
559 pa_log_info("Restoring mute state for sink %s.", new_data->name);
560 pa_sink_new_data_set_muted(new_data, e->muted);
561 new_data->save_muted = TRUE;
562 } else
563 pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
566 entry_free(e);
569 pa_xfree(name);
571 return PA_HOOK_OK;
574 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
575 char *name;
576 struct entry *e;
578 pa_assert(c);
579 pa_assert(new_data);
580 pa_assert(u);
581 pa_assert(u->restore_port);
583 name = pa_sprintf_malloc("source:%s", new_data->name);
585 if ((e = entry_read(u, name))) {
587 if (e->port_valid) {
588 if (!new_data->active_port) {
589 pa_log_info("Restoring port for source %s.", name);
590 pa_source_new_data_set_port(new_data, e->port);
591 new_data->save_port = TRUE;
592 } else
593 pa_log_debug("Not restoring port for source %s, because already set.", name);
596 entry_free(e);
599 pa_xfree(name);
601 return PA_HOOK_OK;
604 static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
605 char *name;
606 struct entry *e;
608 pa_assert(c);
609 pa_assert(new_data);
610 pa_assert(u);
611 pa_assert(u->restore_volume || u->restore_muted);
613 name = pa_sprintf_malloc("source:%s", new_data->name);
615 if ((e = entry_read(u, name))) {
617 if (u->restore_volume && e->volume_valid) {
619 if (!new_data->volume_is_set) {
620 pa_cvolume v;
622 pa_log_info("Restoring volume for source %s.", new_data->name);
624 v = e->volume;
625 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
626 pa_source_new_data_set_volume(new_data, &v);
628 new_data->save_volume = TRUE;
629 } else
630 pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name);
633 if (u->restore_muted && e->muted_valid) {
635 if (!new_data->muted_is_set) {
636 pa_log_info("Restoring mute state for source %s.", new_data->name);
637 pa_source_new_data_set_muted(new_data, e->muted);
638 new_data->save_muted = TRUE;
639 } else
640 pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
643 entry_free(e);
646 pa_xfree(name);
648 return PA_HOOK_OK;
651 #define EXT_VERSION 1
653 static void read_sink_format_reply(struct userdata *u, pa_tagstruct *reply, pa_sink *sink) {
654 struct entry *e;
655 char *name;
657 pa_assert(u);
658 pa_assert(reply);
659 pa_assert(sink);
661 pa_tagstruct_putu32(reply, sink->index);
663 /* Read or create an entry */
664 name = pa_sprintf_malloc("sink:%s", sink->name);
665 if (!(e = entry_read(u, name))) {
666 /* Fake a reply with PCM encoding supported */
667 pa_format_info *f = pa_format_info_new();
669 pa_tagstruct_putu8(reply, 1);
670 f->encoding = PA_ENCODING_PCM;
671 pa_tagstruct_put_format_info(reply, f);
673 pa_format_info_free(f);
674 } else {
675 uint32_t idx;
676 pa_format_info *f;
678 /* Write all the formats from the entry to the reply */
679 pa_tagstruct_putu8(reply, pa_idxset_size(e->formats));
680 PA_IDXSET_FOREACH(f, e->formats, idx) {
681 pa_tagstruct_put_format_info(reply, f);
684 pa_xfree(name);
687 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
688 struct userdata *u;
689 uint32_t command;
690 pa_tagstruct *reply = NULL;
692 pa_assert(p);
693 pa_assert(m);
694 pa_assert(c);
695 pa_assert(t);
697 u = m->userdata;
699 if (pa_tagstruct_getu32(t, &command) < 0)
700 goto fail;
702 reply = pa_tagstruct_new(NULL, 0);
703 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
704 pa_tagstruct_putu32(reply, tag);
706 switch (command) {
707 case SUBCOMMAND_TEST: {
708 if (!pa_tagstruct_eof(t))
709 goto fail;
711 pa_tagstruct_putu32(reply, EXT_VERSION);
712 break;
715 case SUBCOMMAND_SUBSCRIBE: {
717 pa_bool_t enabled;
719 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
720 !pa_tagstruct_eof(t))
721 goto fail;
723 if (enabled)
724 pa_idxset_put(u->subscribed, c, NULL);
725 else
726 pa_idxset_remove_by_data(u->subscribed, c, NULL);
728 break;
731 case SUBCOMMAND_READ_SINK_FORMATS_ALL: {
732 pa_sink *sink;
733 uint32_t idx;
735 if (!pa_tagstruct_eof(t))
736 goto fail;
738 PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
739 read_sink_format_reply(u, reply, sink);
742 break;
744 case SUBCOMMAND_READ_SINK_FORMATS: {
745 uint32_t sink_index;
746 pa_sink *sink;
748 pa_assert(reply);
750 /* Get the sink index and the number of formats from the tagstruct */
751 if (pa_tagstruct_getu32(t, &sink_index) < 0)
752 goto fail;
754 if (!pa_tagstruct_eof(t))
755 goto fail;
757 /* Now find our sink */
758 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
759 goto fail;
761 read_sink_format_reply(u, reply, sink);
763 break;
766 case SUBCOMMAND_SAVE_SINK_FORMATS: {
768 struct entry *e;
769 uint32_t sink_index;
770 char *name;
771 pa_sink *sink;
772 uint8_t i, n_formats;
774 /* Get the sink index and the number of formats from the tagstruct */
775 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
776 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
778 goto fail;
781 /* Now find our sink */
782 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
783 goto fail;
785 /* Read or create an entry */
786 name = pa_sprintf_malloc("sink:%s", sink->name);
787 if (!(e = entry_read(u, name)))
788 e = entry_new(FALSE);
790 /* Read all the formats from our tagstruct */
791 for (i = 0; i < n_formats; ++i) {
792 pa_format_info *f = pa_format_info_new();
793 if (pa_tagstruct_get_format_info(t, f) < 0) {
794 pa_format_info_free(f);
795 pa_xfree(name);
796 goto fail;
798 pa_idxset_put(e->formats, f, NULL);
801 if (!pa_tagstruct_eof(t)) {
802 entry_free(e);
803 pa_xfree(name);
804 goto fail;
807 if (entry_write(u, name, e))
808 trigger_save(u);
809 else
810 pa_log_warn("Could not save format info for sink %s", sink->name);
812 pa_xfree(name);
813 entry_free(e);
815 break;
818 default:
819 goto fail;
822 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
823 return 0;
825 fail:
827 if (reply)
828 pa_tagstruct_free(reply);
830 return -1;
833 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
834 pa_assert(p);
835 pa_assert(c);
836 pa_assert(u);
838 pa_idxset_remove_by_data(u->subscribed, c, NULL);
839 return PA_HOOK_OK;
842 int pa__init(pa_module*m) {
843 pa_modargs *ma = NULL;
844 struct userdata *u;
845 char *fname;
846 pa_sink *sink;
847 pa_source *source;
848 uint32_t idx;
849 pa_bool_t restore_volume = TRUE, restore_muted = TRUE, restore_port = TRUE;
851 pa_assert(m);
853 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
854 pa_log("Failed to parse module arguments");
855 goto fail;
858 if (pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
859 pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
860 pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0) {
861 pa_log("restore_port=, restore_volume= and restore_muted= expect boolean arguments");
862 goto fail;
865 if (!restore_muted && !restore_volume && !restore_port)
866 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring port enabled!");
868 m->userdata = u = pa_xnew0(struct userdata, 1);
869 u->core = m->core;
870 u->module = m;
871 u->restore_volume = restore_volume;
872 u->restore_muted = restore_muted;
873 u->restore_port = restore_port;
875 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
877 u->protocol = pa_native_protocol_get(m->core);
878 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
880 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);
882 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
884 if (restore_port) {
885 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);
886 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);
889 if (restore_muted || restore_volume) {
890 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);
891 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);
894 if (!(fname = pa_state_path("device-volumes", TRUE)))
895 goto fail;
897 if (!(u->database = pa_database_open(fname, TRUE))) {
898 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
899 pa_xfree(fname);
900 goto fail;
903 pa_log_info("Successfully opened database file '%s'.", fname);
904 pa_xfree(fname);
906 for (sink = pa_idxset_first(m->core->sinks, &idx); sink; sink = pa_idxset_next(m->core->sinks, &idx))
907 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
909 for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx))
910 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
912 pa_modargs_free(ma);
913 return 0;
915 fail:
916 pa__done(m);
918 if (ma)
919 pa_modargs_free(ma);
921 return -1;
924 void pa__done(pa_module*m) {
925 struct userdata* u;
927 pa_assert(m);
929 if (!(u = m->userdata))
930 return;
932 if (u->subscription)
933 pa_subscription_free(u->subscription);
935 if (u->sink_fixate_hook_slot)
936 pa_hook_slot_free(u->sink_fixate_hook_slot);
937 if (u->source_fixate_hook_slot)
938 pa_hook_slot_free(u->source_fixate_hook_slot);
939 if (u->sink_new_hook_slot)
940 pa_hook_slot_free(u->sink_new_hook_slot);
941 if (u->source_new_hook_slot)
942 pa_hook_slot_free(u->source_new_hook_slot);
944 if (u->connection_unlink_hook_slot)
945 pa_hook_slot_free(u->connection_unlink_hook_slot);
947 if (u->save_time_event)
948 u->core->mainloop->time_free(u->save_time_event);
950 if (u->database)
951 pa_database_close(u->database);
953 if (u->protocol) {
954 pa_native_protocol_remove_ext(u->protocol, m);
955 pa_native_protocol_unref(u->protocol);
958 if (u->subscribed)
959 pa_idxset_free(u->subscribed, NULL, NULL);
961 pa_xfree(u);