2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
5 Copyright 2009 Tanu Kaskinen
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>
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>
53 #include <pulsecore/tagstruct.h>
54 #include <pulsecore/proplist-util.h>
57 #include <pulsecore/dbus-util.h>
58 #include <pulsecore/protocol-dbus.h>
61 #include "module-stream-restore-symdef.h"
63 PA_MODULE_AUTHOR("Lennart Poettering");
64 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute/device state of streams");
65 PA_MODULE_VERSION(PACKAGE_VERSION);
66 PA_MODULE_LOAD_ONCE(TRUE);
68 "restore_device=<Save/restore sinks/sources?> "
69 "restore_volume=<Save/restore volumes?> "
70 "restore_muted=<Save/restore muted states?> "
71 "on_hotplug=<When new device becomes available, recheck streams?> "
72 "on_rescue=<When device becomes unavailable, recheck streams?> "
73 "fallback_table=<filename>");
75 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
76 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
78 #define DEFAULT_FALLBACK_FILE PA_DEFAULT_CONFIG_DIR"/stream-restore.table"
79 #define DEFAULT_FALLBACK_FILE_USER "stream-restore.table"
81 #define WHITESPACE "\n\r \t"
83 static const char* const valid_modargs[] = {
96 pa_subscription *subscription;
98 *sink_input_new_hook_slot,
99 *sink_input_fixate_hook_slot,
100 *source_output_new_hook_slot,
101 *source_output_fixate_hook_slot,
103 *source_put_hook_slot,
104 *sink_unlink_hook_slot,
105 *source_unlink_hook_slot,
106 *connection_unlink_hook_slot;
107 pa_time_event *save_time_event;
108 pa_database* database;
110 pa_bool_t restore_device:1;
111 pa_bool_t restore_volume:1;
112 pa_bool_t restore_muted:1;
113 pa_bool_t on_hotplug:1;
114 pa_bool_t on_rescue:1;
116 pa_native_protocol *protocol;
117 pa_idxset *subscribed;
120 pa_dbus_protocol *dbus_protocol;
121 pa_hashmap *dbus_entries;
122 uint32_t next_index; /* For generating object paths for entries. */
126 #define ENTRY_VERSION 1
130 pa_bool_t muted_valid, volume_valid, device_valid, card_valid;
132 pa_channel_map channel_map;
143 SUBCOMMAND_SUBSCRIBE,
148 static struct entry* entry_new(void);
149 static void entry_free(struct entry *e);
150 static struct entry *entry_read(struct userdata *u, const char *name);
151 static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e, pa_bool_t replace);
152 static struct entry* entry_copy(const struct entry *e);
153 static void entry_apply(struct userdata *u, const char *name, struct entry *e);
154 static void trigger_save(struct userdata *u);
158 #define OBJECT_PATH "/org/pulseaudio/stream_restore1"
159 #define ENTRY_OBJECT_NAME "entry"
160 #define INTERFACE_STREAM_RESTORE "org.PulseAudio.Ext.StreamRestore1"
161 #define INTERFACE_ENTRY INTERFACE_STREAM_RESTORE ".RestoreEntry"
163 #define DBUS_INTERFACE_REVISION 0
166 struct userdata *userdata;
173 static void handle_get_interface_revision(DBusConnection *conn, DBusMessage *msg, void *userdata);
174 static void handle_get_entries(DBusConnection *conn, DBusMessage *msg, void *userdata);
176 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
178 static void handle_add_entry(DBusConnection *conn, DBusMessage *msg, void *userdata);
179 static void handle_get_entry_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
181 static void handle_entry_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
182 static void handle_entry_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
183 static void handle_entry_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
184 static void handle_entry_set_device(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
185 static void handle_entry_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
186 static void handle_entry_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
187 static void handle_entry_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
188 static void handle_entry_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
190 static void handle_entry_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
192 static void handle_entry_remove(DBusConnection *conn, DBusMessage *msg, void *userdata);
194 enum property_handler_index {
195 PROPERTY_HANDLER_INTERFACE_REVISION,
196 PROPERTY_HANDLER_ENTRIES,
200 enum entry_property_handler_index {
201 ENTRY_PROPERTY_HANDLER_INDEX,
202 ENTRY_PROPERTY_HANDLER_NAME,
203 ENTRY_PROPERTY_HANDLER_DEVICE,
204 ENTRY_PROPERTY_HANDLER_VOLUME,
205 ENTRY_PROPERTY_HANDLER_MUTE,
206 ENTRY_PROPERTY_HANDLER_MAX
209 static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
210 [PROPERTY_HANDLER_INTERFACE_REVISION] = { .property_name = "InterfaceRevision", .type = "u", .get_cb = handle_get_interface_revision, .set_cb = NULL },
211 [PROPERTY_HANDLER_ENTRIES] = { .property_name = "Entries", .type = "ao", .get_cb = handle_get_entries, .set_cb = NULL }
214 static pa_dbus_property_handler entry_property_handlers[ENTRY_PROPERTY_HANDLER_MAX] = {
215 [ENTRY_PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_entry_get_index, .set_cb = NULL },
216 [ENTRY_PROPERTY_HANDLER_NAME] = { .property_name = "Name", .type = "s", .get_cb = handle_entry_get_name, .set_cb = NULL },
217 [ENTRY_PROPERTY_HANDLER_DEVICE] = { .property_name = "Device", .type = "s", .get_cb = handle_entry_get_device, .set_cb = handle_entry_set_device },
218 [ENTRY_PROPERTY_HANDLER_VOLUME] = { .property_name = "Volume", .type = "a(uu)", .get_cb = handle_entry_get_volume, .set_cb = handle_entry_set_volume },
219 [ENTRY_PROPERTY_HANDLER_MUTE] = { .property_name = "Mute", .type = "b", .get_cb = handle_entry_get_mute, .set_cb = handle_entry_set_mute }
222 enum method_handler_index {
223 METHOD_HANDLER_ADD_ENTRY,
224 METHOD_HANDLER_GET_ENTRY_BY_NAME,
228 enum entry_method_handler_index {
229 ENTRY_METHOD_HANDLER_REMOVE,
230 ENTRY_METHOD_HANDLER_MAX
233 static pa_dbus_arg_info add_entry_args[] = { { "name", "s", "in" },
234 { "device", "s", "in" },
235 { "volume", "a(uu)", "in" },
236 { "mute", "b", "in" },
237 { "entry", "o", "out" } };
238 static pa_dbus_arg_info get_entry_by_name_args[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
240 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
241 [METHOD_HANDLER_ADD_ENTRY] = {
242 .method_name = "AddEntry",
243 .arguments = add_entry_args,
244 .n_arguments = sizeof(add_entry_args) / sizeof(pa_dbus_arg_info),
245 .receive_cb = handle_add_entry },
246 [METHOD_HANDLER_GET_ENTRY_BY_NAME] = {
247 .method_name = "GetEntryByName",
248 .arguments = get_entry_by_name_args,
249 .n_arguments = sizeof(get_entry_by_name_args) / sizeof(pa_dbus_arg_info),
250 .receive_cb = handle_get_entry_by_name }
253 static pa_dbus_method_handler entry_method_handlers[ENTRY_METHOD_HANDLER_MAX] = {
254 [ENTRY_METHOD_HANDLER_REMOVE] = {
255 .method_name = "Remove",
258 .receive_cb = handle_entry_remove }
263 SIGNAL_ENTRY_REMOVED,
267 enum entry_signal_index {
268 ENTRY_SIGNAL_DEVICE_UPDATED,
269 ENTRY_SIGNAL_VOLUME_UPDATED,
270 ENTRY_SIGNAL_MUTE_UPDATED,
274 static pa_dbus_arg_info new_entry_args[] = { { "entry", "o", NULL } };
275 static pa_dbus_arg_info entry_removed_args[] = { { "entry", "o", NULL } };
277 static pa_dbus_arg_info entry_device_updated_args[] = { { "device", "s", NULL } };
278 static pa_dbus_arg_info entry_volume_updated_args[] = { { "volume", "a(uu)", NULL } };
279 static pa_dbus_arg_info entry_mute_updated_args[] = { { "muted", "b", NULL } };
281 static pa_dbus_signal_info signals[SIGNAL_MAX] = {
282 [SIGNAL_NEW_ENTRY] = { .name = "NewEntry", .arguments = new_entry_args, .n_arguments = 1 },
283 [SIGNAL_ENTRY_REMOVED] = { .name = "EntryRemoved", .arguments = entry_removed_args, .n_arguments = 1 }
286 static pa_dbus_signal_info entry_signals[ENTRY_SIGNAL_MAX] = {
287 [ENTRY_SIGNAL_DEVICE_UPDATED] = { .name = "DeviceUpdated", .arguments = entry_device_updated_args, .n_arguments = 1 },
288 [ENTRY_SIGNAL_VOLUME_UPDATED] = { .name = "VolumeUpdated", .arguments = entry_volume_updated_args, .n_arguments = 1 },
289 [ENTRY_SIGNAL_MUTE_UPDATED] = { .name = "MuteUpdated", .arguments = entry_mute_updated_args, .n_arguments = 1 }
292 static pa_dbus_interface_info stream_restore_interface_info = {
293 .name = INTERFACE_STREAM_RESTORE,
294 .method_handlers = method_handlers,
295 .n_method_handlers = METHOD_HANDLER_MAX,
296 .property_handlers = property_handlers,
297 .n_property_handlers = PROPERTY_HANDLER_MAX,
298 .get_all_properties_cb = handle_get_all,
300 .n_signals = SIGNAL_MAX
303 static pa_dbus_interface_info entry_interface_info = {
304 .name = INTERFACE_ENTRY,
305 .method_handlers = entry_method_handlers,
306 .n_method_handlers = ENTRY_METHOD_HANDLER_MAX,
307 .property_handlers = entry_property_handlers,
308 .n_property_handlers = ENTRY_PROPERTY_HANDLER_MAX,
309 .get_all_properties_cb = handle_entry_get_all,
310 .signals = entry_signals,
311 .n_signals = ENTRY_SIGNAL_MAX
314 static struct dbus_entry *dbus_entry_new(struct userdata *u, const char *entry_name) {
315 struct dbus_entry *de;
318 pa_assert(entry_name);
319 pa_assert(*entry_name);
321 de = pa_xnew(struct dbus_entry, 1);
323 de->entry_name = pa_xstrdup(entry_name);
324 de->index = u->next_index++;
325 de->object_path = pa_sprintf_malloc("%s/%s%u", OBJECT_PATH, ENTRY_OBJECT_NAME, de->index);
327 pa_assert_se(pa_dbus_protocol_add_interface(u->dbus_protocol, de->object_path, &entry_interface_info, de) >= 0);
332 static void dbus_entry_free(struct dbus_entry *de) {
335 pa_assert_se(pa_dbus_protocol_remove_interface(de->userdata->dbus_protocol, de->object_path, entry_interface_info.name) >= 0);
337 pa_xfree(de->entry_name);
338 pa_xfree(de->object_path);
342 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
343 * are a channel position and a volume value, respectively. The result is
344 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
345 * element. If the data is invalid, an error reply is sent and a negative
346 * number is returned. In case of a failure we make no guarantees about the
347 * state of map and vol. In case of an empty array the channels field of both
348 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
349 * before returning. */
350 static int get_volume_arg(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, pa_channel_map *map, pa_cvolume *vol) {
351 DBusMessageIter array_iter;
352 DBusMessageIter struct_iter;
357 pa_assert(pa_streq(dbus_message_iter_get_signature(iter), "a(uu)"));
361 pa_channel_map_init(map);
362 pa_cvolume_init(vol);
367 dbus_message_iter_recurse(iter, &array_iter);
369 while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID) {
370 dbus_uint32_t chan_pos;
371 dbus_uint32_t chan_vol;
373 dbus_message_iter_recurse(&array_iter, &struct_iter);
375 dbus_message_iter_get_basic(&struct_iter, &chan_pos);
377 if (chan_pos >= PA_CHANNEL_POSITION_MAX) {
378 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid channel position: %u", chan_pos);
382 pa_assert_se(dbus_message_iter_next(&struct_iter));
383 dbus_message_iter_get_basic(&struct_iter, &chan_vol);
385 if (!PA_VOLUME_IS_VALID(chan_vol)) {
386 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", chan_vol);
390 if (map->channels < PA_CHANNELS_MAX) {
391 map->map[map->channels] = chan_pos;
392 vol->values[map->channels] = chan_vol;
397 dbus_message_iter_next(&array_iter);
400 if (map->channels > PA_CHANNELS_MAX) {
401 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too many channels: %u. The maximum is %u.", map->channels, PA_CHANNELS_MAX);
405 dbus_message_iter_next(iter);
410 static void append_volume(DBusMessageIter *iter, struct entry *e) {
411 DBusMessageIter array_iter;
412 DBusMessageIter struct_iter;
418 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(uu)", &array_iter));
420 if (!e->volume_valid) {
421 pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
425 for (i = 0; i < e->channel_map.channels; ++i) {
426 pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter));
428 pa_assert_se(dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_UINT32, &e->channel_map.map[i]));
429 pa_assert_se(dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_UINT32, &e->volume.values[i]));
431 pa_assert_se(dbus_message_iter_close_container(&array_iter, &struct_iter));
434 pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
437 static void append_volume_variant(DBusMessageIter *iter, struct entry *e) {
438 DBusMessageIter variant_iter;
443 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(uu)", &variant_iter));
445 append_volume(&variant_iter, e);
447 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
450 static void send_new_entry_signal(struct dbus_entry *entry) {
451 DBusMessage *signal_msg;
455 pa_assert_se(signal_msg = dbus_message_new_signal(OBJECT_PATH, INTERFACE_STREAM_RESTORE, signals[SIGNAL_NEW_ENTRY].name));
456 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &entry->object_path, DBUS_TYPE_INVALID));
457 pa_dbus_protocol_send_signal(entry->userdata->dbus_protocol, signal_msg);
458 dbus_message_unref(signal_msg);
461 static void send_entry_removed_signal(struct dbus_entry *entry) {
462 DBusMessage *signal_msg;
466 pa_assert_se(signal_msg = dbus_message_new_signal(OBJECT_PATH, INTERFACE_STREAM_RESTORE, signals[SIGNAL_ENTRY_REMOVED].name));
467 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &entry->object_path, DBUS_TYPE_INVALID));
468 pa_dbus_protocol_send_signal(entry->userdata->dbus_protocol, signal_msg);
469 dbus_message_unref(signal_msg);
472 static void send_device_updated_signal(struct dbus_entry *de, struct entry *e) {
473 DBusMessage *signal_msg;
479 device = e->device_valid ? e->device : "";
481 pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_DEVICE_UPDATED].name));
482 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID));
483 pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg);
484 dbus_message_unref(signal_msg);
487 static void send_volume_updated_signal(struct dbus_entry *de, struct entry *e) {
488 DBusMessage *signal_msg;
489 DBusMessageIter msg_iter;
494 pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_VOLUME_UPDATED].name));
495 dbus_message_iter_init_append(signal_msg, &msg_iter);
496 append_volume(&msg_iter, e);
497 pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg);
498 dbus_message_unref(signal_msg);
501 static void send_mute_updated_signal(struct dbus_entry *de, struct entry *e) {
502 DBusMessage *signal_msg;
508 pa_assert(e->muted_valid);
512 pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_MUTE_UPDATED].name));
513 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &muted, DBUS_TYPE_INVALID));
514 pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg);
515 dbus_message_unref(signal_msg);
518 static void handle_get_interface_revision(DBusConnection *conn, DBusMessage *msg, void *userdata) {
519 dbus_uint32_t interface_revision = DBUS_INTERFACE_REVISION;
524 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &interface_revision);
527 /* The caller frees the array, but not the strings. */
528 static const char **get_entries(struct userdata *u, unsigned *n) {
529 const char **entries;
532 struct dbus_entry *de;
537 *n = pa_hashmap_size(u->dbus_entries);
542 entries = pa_xnew(const char *, *n);
544 PA_HASHMAP_FOREACH(de, u->dbus_entries, state)
545 entries[i++] = de->object_path;
550 static void handle_get_entries(DBusConnection *conn, DBusMessage *msg, void *userdata) {
551 struct userdata *u = userdata;
552 const char **entries;
559 entries = get_entries(u, &n);
561 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, entries, n);
566 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
567 struct userdata *u = userdata;
568 DBusMessage *reply = NULL;
569 DBusMessageIter msg_iter;
570 DBusMessageIter dict_iter;
571 dbus_uint32_t interface_revision;
572 const char **entries;
579 interface_revision = DBUS_INTERFACE_REVISION;
580 entries = get_entries(u, &n_entries);
582 pa_assert_se((reply = dbus_message_new_method_return(msg)));
584 dbus_message_iter_init_append(reply, &msg_iter);
585 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
587 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INTERFACE_REVISION].property_name, DBUS_TYPE_UINT32, &interface_revision);
588 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ENTRIES].property_name, DBUS_TYPE_OBJECT_PATH, entries, n_entries);
590 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
592 pa_assert_se(dbus_connection_send(conn, reply, NULL));
594 dbus_message_unref(reply);
599 static void handle_add_entry(DBusConnection *conn, DBusMessage *msg, void *userdata) {
600 struct userdata *u = userdata;
601 DBusMessageIter msg_iter;
602 const char *name = NULL;
603 const char *device = NULL;
606 dbus_bool_t muted = FALSE;
607 dbus_bool_t apply_immediately = FALSE;
608 struct dbus_entry *dbus_entry = NULL;
609 struct entry *e = NULL;
615 pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
616 dbus_message_iter_get_basic(&msg_iter, &name);
618 pa_assert_se(dbus_message_iter_next(&msg_iter));
619 dbus_message_iter_get_basic(&msg_iter, &device);
621 pa_assert_se(dbus_message_iter_next(&msg_iter));
622 if (get_volume_arg(conn, msg, &msg_iter, &map, &vol) < 0)
625 dbus_message_iter_get_basic(&msg_iter, &muted);
627 pa_assert_se(dbus_message_iter_next(&msg_iter));
628 dbus_message_iter_get_basic(&msg_iter, &apply_immediately);
631 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "An empty string was given as the entry name.");
635 if ((dbus_entry = pa_hashmap_get(u->dbus_entries, name))) {
636 pa_bool_t mute_updated = FALSE;
637 pa_bool_t volume_updated = FALSE;
638 pa_bool_t device_updated = FALSE;
640 pa_assert_se(e = entry_read(u, name));
641 mute_updated = e->muted != muted;
643 e->muted_valid = TRUE;
645 volume_updated = (e->volume_valid != !!map.channels) || !pa_cvolume_equal(&e->volume, &vol);
647 e->channel_map = map;
648 e->volume_valid = !!map.channels;
650 device_updated = (e->device_valid != !!device[0]) || !pa_streq(e->device, device);
652 e->device = pa_xstrdup(device);
653 e->device_valid = !!device[0];
656 send_mute_updated_signal(dbus_entry, e);
658 send_volume_updated_signal(dbus_entry, e);
660 send_device_updated_signal(dbus_entry, e);
663 dbus_entry = dbus_entry_new(u, name);
664 pa_assert_se(pa_hashmap_put(u->dbus_entries, dbus_entry->entry_name, dbus_entry) == 0);
667 e->muted_valid = TRUE;
668 e->volume_valid = !!map.channels;
669 e->device_valid = !!device[0];
672 e->channel_map = map;
673 e->device = pa_xstrdup(device);
675 send_new_entry_signal(dbus_entry);
678 pa_assert_se(entry_write(u, name, e, TRUE));
680 if (apply_immediately)
681 entry_apply(u, name, e);
685 pa_dbus_send_empty_reply(conn, msg);
690 static void handle_get_entry_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
691 struct userdata *u = userdata;
693 struct dbus_entry *de;
699 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
701 if (!(de = pa_hashmap_get(u->dbus_entries, name))) {
702 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such stream restore entry.");
706 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &de->object_path);
709 static void handle_entry_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
710 struct dbus_entry *de = userdata;
716 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &de->index);
719 static void handle_entry_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
720 struct dbus_entry *de = userdata;
726 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &de->entry_name);
729 static void handle_entry_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
730 struct dbus_entry *de = userdata;
738 pa_assert_se(e = entry_read(de->userdata, de->entry_name));
740 device = e->device_valid ? e->device : "";
742 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &device);
747 static void handle_entry_set_device(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
748 struct dbus_entry *de = userdata;
758 dbus_message_iter_get_basic(iter, &device);
760 pa_assert_se(e = entry_read(de->userdata, de->entry_name));
762 updated = (e->device_valid != !!device[0]) || !pa_streq(e->device, device);
766 e->device = pa_xstrdup(device);
767 e->device_valid = !!device[0];
769 pa_assert_se(entry_write(de->userdata, de->entry_name, e, TRUE));
771 entry_apply(de->userdata, de->entry_name, e);
772 send_device_updated_signal(de, e);
773 trigger_save(de->userdata);
776 pa_dbus_send_empty_reply(conn, msg);
781 static void handle_entry_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
782 struct dbus_entry *de = userdata;
784 DBusMessageIter msg_iter;
791 pa_assert_se(e = entry_read(de->userdata, de->entry_name));
793 pa_assert_se(reply = dbus_message_new_method_return(msg));
795 dbus_message_iter_init_append(reply, &msg_iter);
796 append_volume_variant(&msg_iter, e);
798 pa_assert_se(dbus_connection_send(conn, reply, NULL));
803 static void handle_entry_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
804 struct dbus_entry *de = userdata;
807 struct entry *e = NULL;
808 pa_bool_t updated = FALSE;
815 if (get_volume_arg(conn, msg, iter, &map, &vol) < 0)
818 pa_assert_se(e = entry_read(de->userdata, de->entry_name));
820 updated = (e->volume_valid != !!map.channels) || !pa_cvolume_equal(&e->volume, &vol);
824 e->channel_map = map;
825 e->volume_valid = !!map.channels;
827 pa_assert_se(entry_write(de->userdata, de->entry_name, e, TRUE));
829 entry_apply(de->userdata, de->entry_name, e);
830 send_volume_updated_signal(de, e);
831 trigger_save(de->userdata);
834 pa_dbus_send_empty_reply(conn, msg);
839 static void handle_entry_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
840 struct dbus_entry *de = userdata;
848 pa_assert_se(e = entry_read(de->userdata, de->entry_name));
850 mute = e->muted_valid ? e->muted : FALSE;
852 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &mute);
857 static void handle_entry_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
858 struct dbus_entry *de = userdata;
868 dbus_message_iter_get_basic(iter, &mute);
870 pa_assert_se(e = entry_read(de->userdata, de->entry_name));
872 updated = !e->muted_valid || e->muted != mute;
876 e->muted_valid = TRUE;
878 pa_assert_se(entry_write(de->userdata, de->entry_name, e, TRUE));
880 entry_apply(de->userdata, de->entry_name, e);
881 send_mute_updated_signal(de, e);
882 trigger_save(de->userdata);
885 pa_dbus_send_empty_reply(conn, msg);
890 static void handle_entry_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
891 struct dbus_entry *de = userdata;
893 DBusMessage *reply = NULL;
894 DBusMessageIter msg_iter;
895 DBusMessageIter dict_iter;
896 DBusMessageIter dict_entry_iter;
904 pa_assert_se(e = entry_read(de->userdata, de->entry_name));
906 device = e->device_valid ? e->device : "";
907 mute = e->muted_valid ? e->muted : FALSE;
909 pa_assert_se((reply = dbus_message_new_method_return(msg)));
911 dbus_message_iter_init_append(reply, &msg_iter);
912 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
914 pa_dbus_append_basic_variant_dict_entry(&dict_iter, entry_property_handlers[ENTRY_PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &de->index);
915 pa_dbus_append_basic_variant_dict_entry(&dict_iter, entry_property_handlers[ENTRY_PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &de->entry_name);
916 pa_dbus_append_basic_variant_dict_entry(&dict_iter, entry_property_handlers[ENTRY_PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_STRING, &device);
918 pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
920 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &entry_property_handlers[ENTRY_PROPERTY_HANDLER_VOLUME].property_name));
921 append_volume_variant(&dict_entry_iter, e);
923 pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
925 pa_dbus_append_basic_variant_dict_entry(&dict_iter, entry_property_handlers[ENTRY_PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &mute);
927 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
929 pa_assert_se(dbus_connection_send(conn, reply, NULL));
931 dbus_message_unref(reply);
936 static void handle_entry_remove(DBusConnection *conn, DBusMessage *msg, void *userdata) {
937 struct dbus_entry *de = userdata;
944 key.data = de->entry_name;
945 key.size = strlen(de->entry_name);
947 pa_assert_se(pa_database_unset(de->userdata->database, &key) == 0);
949 send_entry_removed_signal(de);
950 trigger_save(de->userdata);
952 pa_assert_se(pa_hashmap_remove(de->userdata->dbus_entries, de->entry_name));
955 pa_dbus_send_empty_reply(conn, msg);
958 #endif /* HAVE_DBUS */
960 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
961 struct userdata *u = userdata;
967 pa_assert(e == u->save_time_event);
968 u->core->mainloop->time_free(u->save_time_event);
969 u->save_time_event = NULL;
971 pa_database_sync(u->database);
972 pa_log_info("Synced.");
975 static struct entry* entry_new(void) {
976 struct entry *r = pa_xnew0(struct entry, 1);
977 r->version = ENTRY_VERSION;
981 static void entry_free(struct entry* e) {
989 static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e, pa_bool_t replace) {
998 t = pa_tagstruct_new(NULL, 0);
999 pa_tagstruct_putu8(t, e->version);
1000 pa_tagstruct_put_boolean(t, e->volume_valid);
1001 pa_tagstruct_put_channel_map(t, &e->channel_map);
1002 pa_tagstruct_put_cvolume(t, &e->volume);
1003 pa_tagstruct_put_boolean(t, e->muted_valid);
1004 pa_tagstruct_put_boolean(t, e->muted);
1005 pa_tagstruct_put_boolean(t, e->device_valid);
1006 pa_tagstruct_puts(t, e->device);
1007 pa_tagstruct_put_boolean(t, e->card_valid);
1008 pa_tagstruct_puts(t, e->card);
1010 key.data = (char *) name;
1011 key.size = strlen(name);
1013 data.data = (void*)pa_tagstruct_data(t, &data.size);
1015 r = (pa_database_set(u->database, &key, &data, replace) == 0);
1017 pa_tagstruct_free(t);
1022 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1024 #define LEGACY_ENTRY_VERSION 3
1025 static struct entry* legacy_entry_read(struct userdata *u, pa_datum *data) {
1026 struct legacy_entry {
1028 pa_bool_t muted_valid:1, volume_valid:1, device_valid:1, card_valid:1;
1030 pa_channel_map channel_map;
1032 char device[PA_NAME_MAX];
1033 char card[PA_NAME_MAX];
1035 struct legacy_entry *le;
1041 if (data->size != sizeof(struct legacy_entry)) {
1042 pa_log_debug("Size does not match.");
1046 le = (struct legacy_entry*)data->data;
1048 if (le->version != LEGACY_ENTRY_VERSION) {
1049 pa_log_debug("Version mismatch.");
1053 if (!memchr(le->device, 0, sizeof(le->device))) {
1054 pa_log_warn("Device has missing NUL byte.");
1058 if (!memchr(le->card, 0, sizeof(le->card))) {
1059 pa_log_warn("Card has missing NUL byte.");
1063 if (le->device_valid && !pa_namereg_is_valid_name(le->device)) {
1064 pa_log_warn("Invalid device name stored in database for legacy stream");
1068 if (le->card_valid && !pa_namereg_is_valid_name(le->card)) {
1069 pa_log_warn("Invalid card name stored in database for legacy stream");
1073 if (le->volume_valid && !pa_channel_map_valid(&le->channel_map)) {
1074 pa_log_warn("Invalid channel map stored in database for legacy stream");
1078 if (le->volume_valid && (!pa_cvolume_valid(&le->volume) || !pa_cvolume_compatible_with_channel_map(&le->volume, &le->channel_map))) {
1079 pa_log_warn("Invalid volume stored in database for legacy stream");
1084 e->muted_valid = le->muted_valid;
1085 e->muted = le->muted;
1086 e->volume_valid = le->volume_valid;
1087 e->channel_map = le->channel_map;
1088 e->volume = le->volume;
1089 e->device_valid = le->device_valid;
1090 e->device = pa_xstrdup(le->device);
1091 e->card_valid = le->card_valid;
1092 e->card = pa_xstrdup(le->card);
1097 static struct entry *entry_read(struct userdata *u, const char *name) {
1099 struct entry *e = NULL;
1100 pa_tagstruct *t = NULL;
1101 const char *device, *card;
1106 key.data = (char*) name;
1107 key.size = strlen(name);
1111 if (!pa_database_get(u->database, &key, &data))
1114 t = pa_tagstruct_new(data.data, data.size);
1117 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
1118 e->version > ENTRY_VERSION ||
1119 pa_tagstruct_get_boolean(t, &e->volume_valid) < 0 ||
1120 pa_tagstruct_get_channel_map(t, &e->channel_map) < 0 ||
1121 pa_tagstruct_get_cvolume(t, &e->volume) < 0 ||
1122 pa_tagstruct_get_boolean(t, &e->muted_valid) < 0 ||
1123 pa_tagstruct_get_boolean(t, &e->muted) < 0 ||
1124 pa_tagstruct_get_boolean(t, &e->device_valid) < 0 ||
1125 pa_tagstruct_gets(t, &device) < 0 ||
1126 pa_tagstruct_get_boolean(t, &e->card_valid) < 0 ||
1127 pa_tagstruct_gets(t, &card) < 0) {
1132 e->device = pa_xstrdup(device);
1133 e->card = pa_xstrdup(card);
1135 if (!pa_tagstruct_eof(t))
1138 if (e->device_valid && !pa_namereg_is_valid_name(e->device)) {
1139 pa_log_warn("Invalid device name stored in database for stream %s", name);
1143 if (e->card_valid && !pa_namereg_is_valid_name(e->card)) {
1144 pa_log_warn("Invalid card name stored in database for stream %s", name);
1148 if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
1149 pa_log_warn("Invalid channel map stored in database for stream %s", name);
1153 if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
1154 pa_log_warn("Invalid volume stored in database for stream %s", name);
1158 pa_tagstruct_free(t);
1159 pa_datum_free(&data);
1165 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
1170 pa_tagstruct_free(t);
1172 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1173 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name);
1174 if ((e = legacy_entry_read(u, &data))) {
1175 pa_log_debug("Success. Saving new format for key: %s", name);
1176 if (entry_write(u, name, e, TRUE))
1178 pa_datum_free(&data);
1181 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name);
1184 pa_datum_free(&data);
1188 static struct entry* entry_copy(const struct entry *e) {
1194 r->device = pa_xstrdup(e->device);
1195 r->card = pa_xstrdup(e->card);
1199 static void trigger_save(struct userdata *u) {
1200 pa_native_connection *c;
1203 for (c = pa_idxset_first(u->subscribed, &idx); c; c = pa_idxset_next(u->subscribed, &idx)) {
1206 t = pa_tagstruct_new(NULL, 0);
1207 pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
1208 pa_tagstruct_putu32(t, 0);
1209 pa_tagstruct_putu32(t, u->module->index);
1210 pa_tagstruct_puts(t, u->module->name);
1211 pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
1213 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
1216 if (u->save_time_event)
1219 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
1222 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
1228 if (a->device_valid != b->device_valid ||
1229 (a->device_valid && !pa_streq(a->device, b->device)))
1232 if (a->card_valid != b->card_valid ||
1233 (a->card_valid && !pa_streq(a->card, b->card)))
1236 if (a->muted_valid != b->muted_valid ||
1237 (a->muted_valid && (a->muted != b->muted)))
1241 if (a->volume_valid != b->volume_valid ||
1242 (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
1248 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
1249 struct userdata *u = userdata;
1250 struct entry *entry, *old = NULL;
1253 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1254 * clutter these are defined here unconditionally. */
1255 pa_bool_t created_new_entry = TRUE;
1256 pa_bool_t device_updated = FALSE;
1257 pa_bool_t volume_updated = FALSE;
1258 pa_bool_t mute_updated = FALSE;
1261 struct dbus_entry *de = NULL;
1267 if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
1268 t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
1269 t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
1270 t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE))
1273 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
1274 pa_sink_input *sink_input;
1276 if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx)))
1279 if (!(name = pa_proplist_get_stream_group(sink_input->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
1282 if ((old = entry_read(u, name))) {
1283 entry = entry_copy(old);
1284 created_new_entry = FALSE;
1286 entry = entry_new();
1288 if (sink_input->save_volume && pa_sink_input_is_volume_readable(sink_input)) {
1289 pa_assert(sink_input->volume_writable);
1291 entry->channel_map = sink_input->channel_map;
1292 pa_sink_input_get_volume(sink_input, &entry->volume, FALSE);
1293 entry->volume_valid = TRUE;
1295 volume_updated = !created_new_entry
1296 && (!old->volume_valid
1297 || !pa_channel_map_equal(&entry->channel_map, &old->channel_map)
1298 || !pa_cvolume_equal(&entry->volume, &old->volume));
1301 if (sink_input->save_muted) {
1302 entry->muted = pa_sink_input_get_mute(sink_input);
1303 entry->muted_valid = TRUE;
1305 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted);
1308 if (sink_input->save_sink) {
1309 pa_xfree(entry->device);
1310 entry->device = pa_xstrdup(sink_input->sink->name);
1311 entry->device_valid = TRUE;
1313 device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device));
1314 if (sink_input->sink->card) {
1315 pa_xfree(entry->card);
1316 entry->card = pa_xstrdup(sink_input->sink->card->name);
1317 entry->card_valid = TRUE;
1322 pa_source_output *source_output;
1324 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT);
1326 if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx)))
1329 if (!(name = pa_proplist_get_stream_group(source_output->proplist, "source-output", IDENTIFICATION_PROPERTY)))
1332 if ((old = entry_read(u, name))) {
1333 entry = entry_copy(old);
1334 created_new_entry = FALSE;
1336 entry = entry_new();
1338 if (source_output->save_volume && pa_source_output_is_volume_readable(source_output)) {
1339 pa_assert(source_output->volume_writable);
1341 entry->channel_map = source_output->channel_map;
1342 pa_source_output_get_volume(source_output, &entry->volume, FALSE);
1343 entry->volume_valid = TRUE;
1345 volume_updated = !created_new_entry
1346 && (!old->volume_valid
1347 || !pa_channel_map_equal(&entry->channel_map, &old->channel_map)
1348 || !pa_cvolume_equal(&entry->volume, &old->volume));
1351 if (source_output->save_muted) {
1352 entry->muted = pa_source_output_get_mute(source_output);
1353 entry->muted_valid = TRUE;
1355 mute_updated = !created_new_entry && (!old->muted_valid || entry->muted != old->muted);
1358 if (source_output->save_source) {
1359 pa_xfree(entry->device);
1360 entry->device = pa_xstrdup(source_output->source->name);
1361 entry->device_valid = TRUE;
1363 device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry->device, old->device));
1365 if (source_output->source->card) {
1366 pa_xfree(entry->card);
1367 entry->card = pa_xstrdup(source_output->source->card->name);
1368 entry->card_valid = TRUE;
1377 if (entries_equal(old, entry)) {
1387 pa_log_info("Storing volume/mute/device for stream %s.", name);
1389 if (entry_write(u, name, entry, TRUE))
1393 if (created_new_entry) {
1394 de = dbus_entry_new(u, name);
1395 pa_assert_se(pa_hashmap_put(u->dbus_entries, de->entry_name, de) == 0);
1396 send_new_entry_signal(de);
1398 pa_assert_se(de = pa_hashmap_get(u->dbus_entries, name));
1401 send_device_updated_signal(de, entry);
1403 send_volume_updated_signal(de, entry);
1405 send_mute_updated_signal(de, entry);
1413 static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
1418 pa_assert(new_data);
1420 pa_assert(u->restore_device);
1422 if (!(name = pa_proplist_get_stream_group(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
1426 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name, new_data->sink->name);
1427 else if ((e = entry_read(u, name))) {
1430 if (e->device_valid)
1431 s = pa_namereg_get(c, e->device, PA_NAMEREG_SINK);
1433 if (!s && e->card_valid) {
1436 if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD)))
1437 s = pa_idxset_first(card->sinks, NULL);
1440 /* It might happen that a stream and a sink are set up at the
1441 same time, in which case we want to make sure we don't
1442 interfere with that */
1443 if (s && PA_SINK_IS_LINKED(pa_sink_get_state(s)))
1444 if (pa_sink_input_new_data_set_sink(new_data, s, TRUE))
1445 pa_log_info("Restoring device for stream %s.", name);
1455 static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
1460 pa_assert(new_data);
1462 pa_assert(u->restore_volume || u->restore_muted);
1464 if (!(name = pa_proplist_get_stream_group(new_data->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
1467 if ((e = entry_read(u, name))) {
1469 if (u->restore_volume && e->volume_valid) {
1470 if (!new_data->volume_writable)
1471 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name);
1472 else if (new_data->volume_is_set)
1473 pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
1477 pa_log_info("Restoring volume for sink input %s.", name);
1480 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
1481 pa_sink_input_new_data_set_volume(new_data, &v);
1483 new_data->volume_is_absolute = FALSE;
1484 new_data->save_volume = TRUE;
1488 if (u->restore_muted && e->muted_valid) {
1490 if (!new_data->muted_is_set) {
1491 pa_log_info("Restoring mute state for sink input %s.", name);
1492 pa_sink_input_new_data_set_muted(new_data, e->muted);
1493 new_data->save_muted = TRUE;
1495 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name);
1506 static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
1511 pa_assert(new_data);
1513 pa_assert(u->restore_device);
1515 if (new_data->direct_on_input)
1518 if (!(name = pa_proplist_get_stream_group(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY)))
1521 if (new_data->source)
1522 pa_log_debug("Not restoring device for stream %s, because already set", name);
1523 else if ((e = entry_read(u, name))) {
1524 pa_source *s = NULL;
1526 if (e->device_valid)
1527 s = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE);
1529 if (!s && e->card_valid) {
1532 if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD)))
1533 s = pa_idxset_first(card->sources, NULL);
1536 /* It might happen that a stream and a sink are set up at the
1537 same time, in which case we want to make sure we don't
1538 interfere with that */
1539 if (s && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) {
1540 pa_log_info("Restoring device for stream %s.", name);
1541 pa_source_output_new_data_set_source(new_data, s, TRUE);
1552 static pa_hook_result_t source_output_fixate_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
1557 pa_assert(new_data);
1559 pa_assert(u->restore_volume || u->restore_muted);
1561 if (!(name = pa_proplist_get_stream_group(new_data->proplist, "source-output", IDENTIFICATION_PROPERTY)))
1564 if ((e = entry_read(u, name))) {
1566 if (u->restore_volume && e->volume_valid) {
1567 if (!new_data->volume_writable)
1568 pa_log_debug("Not restoring volume for source output %s, because its volume can't be changed.", name);
1569 else if (new_data->volume_is_set)
1570 pa_log_debug("Not restoring volume for source output %s, because already set.", name);
1574 pa_log_info("Restoring volume for source output %s.", name);
1577 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
1578 pa_source_output_new_data_set_volume(new_data, &v);
1580 new_data->volume_is_absolute = FALSE;
1581 new_data->save_volume = TRUE;
1585 if (u->restore_muted && e->muted_valid) {
1587 if (!new_data->muted_is_set) {
1588 pa_log_info("Restoring mute state for source output %s.", name);
1589 pa_source_output_new_data_set_muted(new_data, e->muted);
1590 new_data->save_muted = TRUE;
1592 pa_log_debug("Not restoring mute state for source output %s, because already set.", name);
1603 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
1610 pa_assert(u->on_hotplug && u->restore_device);
1612 PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
1616 if (si->sink == sink)
1622 /* Skip this if it is already in the process of being moved
1627 /* It might happen that a stream and a sink are set up at the
1628 same time, in which case we want to make sure we don't
1629 interfere with that */
1630 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
1633 if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
1636 if ((e = entry_read(u, name))) {
1637 if (e->device_valid && pa_streq(e->device, sink->name))
1638 pa_sink_input_move_to(si, sink, TRUE);
1649 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
1650 pa_source_output *so;
1656 pa_assert(u->on_hotplug && u->restore_device);
1658 PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
1662 if (so->source == source)
1665 if (so->save_source)
1668 if (so->direct_on_input)
1671 /* Skip this if it is already in the process of being moved anyway */
1675 /* It might happen that a stream and a source are set up at the
1676 same time, in which case we want to make sure we don't
1677 interfere with that */
1678 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
1681 if (!(name = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
1684 if ((e = entry_read(u, name))) {
1685 if (e->device_valid && pa_streq(e->device, source->name))
1686 pa_source_output_move_to(so, source, TRUE);
1697 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
1704 pa_assert(u->on_rescue && u->restore_device);
1706 /* There's no point in doing anything if the core is shut down anyway */
1707 if (c->state == PA_CORE_SHUTDOWN)
1710 PA_IDXSET_FOREACH(si, sink->inputs, idx) {
1717 if (!(name = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
1720 if ((e = entry_read(u, name))) {
1722 if (e->device_valid) {
1725 if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) &&
1727 PA_SINK_IS_LINKED(pa_sink_get_state(d)))
1728 pa_sink_input_move_to(si, d, TRUE);
1740 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
1741 pa_source_output *so;
1747 pa_assert(u->on_rescue && u->restore_device);
1749 /* There's no point in doing anything if the core is shut down anyway */
1750 if (c->state == PA_CORE_SHUTDOWN)
1753 PA_IDXSET_FOREACH(so, source->outputs, idx) {
1757 if (so->direct_on_input)
1763 if (!(name = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
1766 if ((e = entry_read(u, name))) {
1768 if (e->device_valid) {
1771 if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) &&
1773 PA_SOURCE_IS_LINKED(pa_source_get_state(d)))
1774 pa_source_output_move_to(so, d, TRUE);
1786 static int fill_db(struct userdata *u, const char *filename) {
1795 f = fopen(fn = pa_xstrdup(filename), "r");
1797 f = pa_open_config_file(DEFAULT_FALLBACK_FILE, DEFAULT_FALLBACK_FILE_USER, NULL, &fn);
1801 pa_log("Failed to open %s: %s", filename, pa_cstrerror(errno));
1813 if (!fgets(ln, sizeof(ln), f))
1820 if (!*ln || ln[0] == '#' || ln[0] == ';')
1823 d = ln+strcspn(ln, WHITESPACE);
1824 v = d+strspn(d, WHITESPACE);
1827 pa_log("[%s:%u] failed to parse line - too few words", fn, n);
1832 if (pa_atod(v, &db) >= 0) {
1838 e.version = ENTRY_VERSION;
1839 e.volume_valid = TRUE;
1840 pa_cvolume_set(&e.volume, 1, pa_sw_volume_from_dB(db));
1841 pa_channel_map_init_mono(&e.channel_map);
1843 key.data = (void *) ln;
1844 key.size = strlen(ln);
1846 data.data = (void *) &e;
1847 data.size = sizeof(e);
1849 if (pa_database_set(u->database, &key, &data, FALSE) == 0)
1850 pa_log_debug("Setting %s to %0.2f dB.", ln, db);
1852 pa_log_warn("[%s:%u] Positive dB values are not allowed, not setting entry %s.", fn, n, ln);
1854 pa_log_warn("[%s:%u] Couldn't parse '%s' as a double, not setting entry %s.", fn, n, v, ln);
1869 static void entry_apply(struct userdata *u, const char *name, struct entry *e) {
1871 pa_source_output *so;
1878 PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
1882 if (!(n = pa_proplist_get_stream_group(si->proplist, "sink-input", IDENTIFICATION_PROPERTY)))
1885 if (!pa_streq(name, n)) {
1891 if (u->restore_volume && e->volume_valid && si->volume_writable) {
1895 pa_log_info("Restoring volume for sink input %s.", name);
1896 pa_cvolume_remap(&v, &e->channel_map, &si->channel_map);
1897 pa_sink_input_set_volume(si, &v, TRUE, FALSE);
1900 if (u->restore_muted && e->muted_valid) {
1901 pa_log_info("Restoring mute state for sink input %s.", name);
1902 pa_sink_input_set_mute(si, e->muted, TRUE);
1905 if (u->restore_device) {
1906 if (!e->device_valid) {
1907 if (si->save_sink) {
1908 pa_log_info("Ensuring device is not saved for stream %s.", name);
1909 /* If the device is not valid we should make sure the
1910 save flag is cleared as the user may have specifically
1911 removed the sink element from the rule. */
1912 si->save_sink = FALSE;
1913 /* This is cheating a bit. The sink input itself has not changed
1914 but the rules governing it's routing have, so we fire this event
1915 such that other routing modules (e.g. module-device-manager)
1916 will pick up the change and reapply their routing */
1917 pa_subscription_post(si->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, si->index);
1919 } else if ((s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SINK))) {
1920 pa_log_info("Restoring device for stream %s.", name);
1921 pa_sink_input_move_to(si, s, TRUE);
1926 PA_IDXSET_FOREACH(so, u->core->source_outputs, idx) {
1930 if (!(n = pa_proplist_get_stream_group(so->proplist, "source-output", IDENTIFICATION_PROPERTY)))
1933 if (!pa_streq(name, n)) {
1939 if (u->restore_volume && e->volume_valid && so->volume_writable) {
1943 pa_log_info("Restoring volume for source output %s.", name);
1944 pa_cvolume_remap(&v, &e->channel_map, &so->channel_map);
1945 pa_source_output_set_volume(so, &v, TRUE, FALSE);
1948 if (u->restore_muted && e->muted_valid) {
1949 pa_log_info("Restoring mute state for source output %s.", name);
1950 pa_source_output_set_mute(so, e->muted, TRUE);
1953 if (u->restore_device) {
1954 if (!e->device_valid) {
1955 if (so->save_source) {
1956 pa_log_info("Ensuring device is not saved for stream %s.", name);
1957 /* If the device is not valid we should make sure the
1958 save flag is cleared as the user may have specifically
1959 removed the source element from the rule. */
1960 so->save_source = FALSE;
1961 /* This is cheating a bit. The source output itself has not changed
1962 but the rules governing it's routing have, so we fire this event
1963 such that other routing modules (e.g. module-device-manager)
1964 will pick up the change and reapply their routing */
1965 pa_subscription_post(so->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, so->index);
1967 } else if ((s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SOURCE))) {
1968 pa_log_info("Restoring device for stream %s.", name);
1969 pa_source_output_move_to(so, s, TRUE);
1976 PA_GCC_UNUSED static void stream_restore_dump_database(struct userdata *u) {
1980 done = !pa_database_first(u->database, &key, NULL);
1987 done = !pa_database_next(u->database, &key, &next_key, NULL);
1989 name = pa_xstrndup(key.data, key.size);
1990 pa_datum_free(&key);
1992 if ((e = entry_read(u, name))) {
1994 pa_log("name=%s", name);
1995 pa_log("device=%s %s", e->device, pa_yes_no(e->device_valid));
1996 pa_log("channel_map=%s", pa_channel_map_snprint(t, sizeof(t), &e->channel_map));
1997 pa_log("volume=%s %s", pa_cvolume_snprint(t, sizeof(t), &e->volume), pa_yes_no(e->volume_valid));
1998 pa_log("mute=%s %s", pa_yes_no(e->muted), pa_yes_no(e->volume_valid));
2009 #define EXT_VERSION 1
2011 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
2014 pa_tagstruct *reply = NULL;
2023 if (pa_tagstruct_getu32(t, &command) < 0)
2026 reply = pa_tagstruct_new(NULL, 0);
2027 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
2028 pa_tagstruct_putu32(reply, tag);
2031 case SUBCOMMAND_TEST: {
2032 if (!pa_tagstruct_eof(t))
2035 pa_tagstruct_putu32(reply, EXT_VERSION);
2039 case SUBCOMMAND_READ: {
2043 if (!pa_tagstruct_eof(t))
2046 done = !pa_database_first(u->database, &key, NULL);
2053 done = !pa_database_next(u->database, &key, &next_key, NULL);
2055 name = pa_xstrndup(key.data, key.size);
2056 pa_datum_free(&key);
2058 if ((e = entry_read(u, name))) {
2062 pa_tagstruct_puts(reply, name);
2063 pa_tagstruct_put_channel_map(reply, e->volume_valid ? &e->channel_map : pa_channel_map_init(&cm));
2064 pa_tagstruct_put_cvolume(reply, e->volume_valid ? &e->volume : pa_cvolume_init(&r));
2065 pa_tagstruct_puts(reply, e->device_valid ? e->device : NULL);
2066 pa_tagstruct_put_boolean(reply, e->muted_valid ? e->muted : FALSE);
2079 case SUBCOMMAND_WRITE: {
2081 pa_bool_t apply_immediately = FALSE;
2083 if (pa_tagstruct_getu32(t, &mode) < 0 ||
2084 pa_tagstruct_get_boolean(t, &apply_immediately) < 0)
2087 if (mode != PA_UPDATE_MERGE &&
2088 mode != PA_UPDATE_REPLACE &&
2089 mode != PA_UPDATE_SET)
2092 if (mode == PA_UPDATE_SET) {
2094 struct dbus_entry *de;
2097 PA_HASHMAP_FOREACH(de, u->dbus_entries, state) {
2098 send_entry_removed_signal(de);
2099 dbus_entry_free(pa_hashmap_remove(u->dbus_entries, de->entry_name));
2102 pa_database_clear(u->database);
2105 while (!pa_tagstruct_eof(t)) {
2106 const char *name, *device;
2108 struct entry *entry;
2113 entry = entry_new();
2115 if (pa_tagstruct_gets(t, &name) < 0 ||
2116 pa_tagstruct_get_channel_map(t, &entry->channel_map) ||
2117 pa_tagstruct_get_cvolume(t, &entry->volume) < 0 ||
2118 pa_tagstruct_gets(t, &device) < 0 ||
2119 pa_tagstruct_get_boolean(t, &muted) < 0)
2122 if (!name || !*name) {
2127 entry->volume_valid = entry->volume.channels > 0;
2129 if (entry->volume_valid)
2130 if (!pa_cvolume_compatible_with_channel_map(&entry->volume, &entry->channel_map)) {
2135 entry->muted = muted;
2136 entry->muted_valid = TRUE;
2138 entry->device = pa_xstrdup(device);
2139 entry->device_valid = device && !!entry->device[0];
2141 if (entry->device_valid && !pa_namereg_is_valid_name(entry->device)) {
2147 old = entry_read(u, name);
2150 pa_log_debug("Client %s changes entry %s.",
2151 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c)->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)),
2154 if (entry_write(u, name, entry, mode == PA_UPDATE_REPLACE)) {
2156 struct dbus_entry *de;
2159 pa_assert_se((de = pa_hashmap_get(u->dbus_entries, name)));
2161 if ((old->device_valid != entry->device_valid)
2162 || (entry->device_valid && !pa_streq(entry->device, old->device)))
2163 send_device_updated_signal(de, entry);
2165 if ((old->volume_valid != entry->volume_valid)
2166 || (entry->volume_valid && (!pa_cvolume_equal(&entry->volume, &old->volume)
2167 || !pa_channel_map_equal(&entry->channel_map, &old->channel_map))))
2168 send_volume_updated_signal(de, entry);
2170 if (!old->muted_valid || (entry->muted != old->muted))
2171 send_mute_updated_signal(de, entry);
2174 de = dbus_entry_new(u, name);
2175 pa_assert_se(pa_hashmap_put(u->dbus_entries, de->entry_name, de) == 0);
2176 send_new_entry_signal(de);
2180 if (apply_immediately)
2181 entry_apply(u, name, entry);
2196 case SUBCOMMAND_DELETE:
2198 while (!pa_tagstruct_eof(t)) {
2202 struct dbus_entry *de;
2205 if (pa_tagstruct_gets(t, &name) < 0)
2209 if ((de = pa_hashmap_get(u->dbus_entries, name))) {
2210 send_entry_removed_signal(de);
2211 dbus_entry_free(pa_hashmap_remove(u->dbus_entries, name));
2215 key.data = (char*) name;
2216 key.size = strlen(name);
2218 pa_database_unset(u->database, &key);
2225 case SUBCOMMAND_SUBSCRIBE: {
2229 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
2230 !pa_tagstruct_eof(t))
2234 pa_idxset_put(u->subscribed, c, NULL);
2236 pa_idxset_remove_by_data(u->subscribed, c, NULL);
2245 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
2251 pa_tagstruct_free(reply);
2256 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
2261 pa_idxset_remove_by_data(u->subscribed, c, NULL);
2265 int pa__init(pa_module*m) {
2266 pa_modargs *ma = NULL;
2270 pa_source_output *so;
2272 pa_bool_t restore_device = TRUE, restore_volume = TRUE, restore_muted = TRUE, on_hotplug = TRUE, on_rescue = TRUE;
2280 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
2281 pa_log("Failed to parse module arguments");
2285 if (pa_modargs_get_value_boolean(ma, "restore_device", &restore_device) < 0 ||
2286 pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
2287 pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
2288 pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
2289 pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
2290 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2294 if (!restore_muted && !restore_volume && !restore_device)
2295 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2297 m->userdata = u = pa_xnew0(struct userdata, 1);
2300 u->restore_device = restore_device;
2301 u->restore_volume = restore_volume;
2302 u->restore_muted = restore_muted;
2303 u->on_hotplug = on_hotplug;
2304 u->on_rescue = on_rescue;
2305 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2307 u->protocol = pa_native_protocol_get(m->core);
2308 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
2310 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);
2312 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
2314 if (restore_device) {
2315 /* A little bit earlier than module-intended-roles ... */
2316 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);
2317 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);
2320 if (restore_device && on_hotplug) {
2321 /* A little bit earlier than module-intended-roles ... */
2322 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);
2323 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);
2326 if (restore_device && on_rescue) {
2327 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2328 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);
2329 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);
2332 if (restore_volume || restore_muted) {
2333 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);
2334 u->source_output_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_fixate_hook_callback, u);
2337 if (!(fname = pa_state_path("stream-volumes", TRUE)))
2340 if (!(u->database = pa_database_open(fname, TRUE))) {
2341 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
2346 pa_log_info("Successfully opened database file '%s'.", fname);
2349 if (fill_db(u, pa_modargs_get_value(ma, "fallback_table", NULL)) < 0)
2353 u->dbus_protocol = pa_dbus_protocol_get(u->core);
2354 u->dbus_entries = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2356 pa_assert_se(pa_dbus_protocol_add_interface(u->dbus_protocol, OBJECT_PATH, &stream_restore_interface_info, u) >= 0);
2357 pa_assert_se(pa_dbus_protocol_register_extension(u->dbus_protocol, INTERFACE_STREAM_RESTORE) >= 0);
2359 /* Create the initial dbus entries. */
2360 done = !pa_database_first(u->database, &key, NULL);
2364 struct dbus_entry *de;
2367 done = !pa_database_next(u->database, &key, &next_key, NULL);
2369 name = pa_xstrndup(key.data, key.size);
2370 pa_datum_free(&key);
2372 /* Use entry_read() for checking that the entry is valid. */
2373 if ((e = entry_read(u, name))) {
2374 de = dbus_entry_new(u, name);
2375 pa_assert_se(pa_hashmap_put(u->dbus_entries, de->entry_name, de) == 0);
2385 PA_IDXSET_FOREACH(si, m->core->sink_inputs, idx)
2386 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, si->index, u);
2388 PA_IDXSET_FOREACH(so, m->core->source_outputs, idx)
2389 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, so->index, u);
2391 pa_modargs_free(ma);
2398 pa_modargs_free(ma);
2404 static void free_dbus_entry_cb(void *p, void *userdata) {
2405 struct dbus_entry *de = p;
2409 dbus_entry_free(de);
2413 void pa__done(pa_module*m) {
2418 if (!(u = m->userdata))
2422 if (u->dbus_protocol) {
2423 pa_assert(u->dbus_entries);
2425 pa_assert_se(pa_dbus_protocol_unregister_extension(u->dbus_protocol, INTERFACE_STREAM_RESTORE) >= 0);
2426 pa_assert_se(pa_dbus_protocol_remove_interface(u->dbus_protocol, OBJECT_PATH, stream_restore_interface_info.name) >= 0);
2428 pa_hashmap_free(u->dbus_entries, free_dbus_entry_cb, NULL);
2430 pa_dbus_protocol_unref(u->dbus_protocol);
2434 if (u->subscription)
2435 pa_subscription_free(u->subscription);
2437 if (u->sink_input_new_hook_slot)
2438 pa_hook_slot_free(u->sink_input_new_hook_slot);
2439 if (u->sink_input_fixate_hook_slot)
2440 pa_hook_slot_free(u->sink_input_fixate_hook_slot);
2441 if (u->source_output_new_hook_slot)
2442 pa_hook_slot_free(u->source_output_new_hook_slot);
2443 if (u->source_output_fixate_hook_slot)
2444 pa_hook_slot_free(u->source_output_fixate_hook_slot);
2446 if (u->sink_put_hook_slot)
2447 pa_hook_slot_free(u->sink_put_hook_slot);
2448 if (u->source_put_hook_slot)
2449 pa_hook_slot_free(u->source_put_hook_slot);
2451 if (u->sink_unlink_hook_slot)
2452 pa_hook_slot_free(u->sink_unlink_hook_slot);
2453 if (u->source_unlink_hook_slot)
2454 pa_hook_slot_free(u->source_unlink_hook_slot);
2456 if (u->connection_unlink_hook_slot)
2457 pa_hook_slot_free(u->connection_unlink_hook_slot);
2459 if (u->save_time_event)
2460 u->core->mainloop->time_free(u->save_time_event);
2463 pa_database_close(u->database);
2466 pa_native_protocol_remove_ext(u->protocol, m);
2467 pa_native_protocol_unref(u->protocol);
2471 pa_idxset_free(u->subscribed, NULL, NULL);