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>
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/util.h>
39 #include <pulse/rtclock.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/modargs.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/core-subscribe.h>
47 #include <pulsecore/sink-input.h>
48 #include <pulsecore/source-output.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/protocol-native.h>
51 #include <pulsecore/pstream.h>
52 #include <pulsecore/pstream-util.h>
53 #include <pulsecore/database.h>
56 #include <pulsecore/dbus-util.h>
57 #include <pulsecore/protocol-dbus.h>
60 #include "module-stream-restore-symdef.h"
62 PA_MODULE_AUTHOR("Lennart Poettering");
63 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute/device state of streams");
64 PA_MODULE_VERSION(PACKAGE_VERSION);
65 PA_MODULE_LOAD_ONCE(TRUE);
67 "restore_device=<Save/restore sinks/sources?> "
68 "restore_volume=<Save/restore volumes?> "
69 "restore_muted=<Save/restore muted states?> "
70 "on_hotplug=<When new device becomes available, recheck streams?> "
71 "on_rescue=<When device becomes unavailable, recheck streams?>");
73 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
74 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
76 static const char* const valid_modargs[] = {
88 pa_subscription *subscription;
90 *sink_input_new_hook_slot,
91 *sink_input_fixate_hook_slot,
92 *source_output_new_hook_slot,
94 *source_put_hook_slot,
95 *sink_unlink_hook_slot,
96 *source_unlink_hook_slot,
97 *connection_unlink_hook_slot;
98 pa_time_event *save_time_event;
99 pa_database* database;
101 pa_bool_t restore_device:1;
102 pa_bool_t restore_volume:1;
103 pa_bool_t restore_muted:1;
104 pa_bool_t on_hotplug:1;
105 pa_bool_t on_rescue:1;
107 pa_native_protocol *protocol;
108 pa_idxset *subscribed;
111 pa_dbus_protocol *dbus_protocol;
112 pa_hashmap *dbus_entries;
113 uint32_t next_index; /* For generating object paths for entries. */
117 #define ENTRY_VERSION 3
121 pa_bool_t muted_valid:1, volume_valid:1, device_valid:1, card_valid:1;
123 pa_channel_map channel_map;
125 char device[PA_NAME_MAX];
126 char card[PA_NAME_MAX];
134 SUBCOMMAND_SUBSCRIBE,
138 static struct entry *read_entry(struct userdata *u, const char *name);
139 static void apply_entry(struct userdata *u, const char *name, struct entry *e);
140 static void trigger_save(struct userdata *u);
144 #define OBJECT_PATH "/org/pulseaudio/stream_restore1"
145 #define ENTRY_OBJECT_NAME "entry"
146 #define INTERFACE_STREAM_RESTORE "org.PulseAudio.Ext.StreamRestore1"
147 #define INTERFACE_ENTRY INTERFACE_STREAM_RESTORE ".RestoreEntry"
149 #define DBUS_INTERFACE_REVISION 0
152 struct userdata *userdata;
159 static void handle_get_interface_revision(DBusConnection *conn, DBusMessage *msg, void *userdata);
160 static void handle_get_entries(DBusConnection *conn, DBusMessage *msg, void *userdata);
162 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
164 static void handle_add_entry(DBusConnection *conn, DBusMessage *msg, void *userdata);
165 static void handle_get_entry_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
167 static void handle_entry_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
168 static void handle_entry_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
169 static void handle_entry_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
170 static void handle_entry_set_device(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
171 static void handle_entry_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
172 static void handle_entry_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
173 static void handle_entry_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
174 static void handle_entry_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
176 static void handle_entry_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
178 static void handle_entry_remove(DBusConnection *conn, DBusMessage *msg, void *userdata);
180 enum property_handler_index {
181 PROPERTY_HANDLER_INTERFACE_REVISION,
182 PROPERTY_HANDLER_ENTRIES,
186 enum entry_property_handler_index {
187 ENTRY_PROPERTY_HANDLER_INDEX,
188 ENTRY_PROPERTY_HANDLER_NAME,
189 ENTRY_PROPERTY_HANDLER_DEVICE,
190 ENTRY_PROPERTY_HANDLER_VOLUME,
191 ENTRY_PROPERTY_HANDLER_MUTE,
192 ENTRY_PROPERTY_HANDLER_MAX
195 static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
196 [PROPERTY_HANDLER_INTERFACE_REVISION] = { .property_name = "InterfaceRevision", .type = "u", .get_cb = handle_get_interface_revision, .set_cb = NULL },
197 [PROPERTY_HANDLER_ENTRIES] = { .property_name = "Entries", .type = "ao", .get_cb = handle_get_entries, .set_cb = NULL }
200 static pa_dbus_property_handler entry_property_handlers[ENTRY_PROPERTY_HANDLER_MAX] = {
201 [ENTRY_PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_entry_get_index, .set_cb = NULL },
202 [ENTRY_PROPERTY_HANDLER_NAME] = { .property_name = "Name", .type = "s", .get_cb = handle_entry_get_name, .set_cb = NULL },
203 [ENTRY_PROPERTY_HANDLER_DEVICE] = { .property_name = "Device", .type = "s", .get_cb = handle_entry_get_device, .set_cb = handle_entry_set_device },
204 [ENTRY_PROPERTY_HANDLER_VOLUME] = { .property_name = "Volume", .type = "a(uu)", .get_cb = handle_entry_get_volume, .set_cb = handle_entry_set_volume },
205 [ENTRY_PROPERTY_HANDLER_MUTE] = { .property_name = "Mute", .type = "b", .get_cb = handle_entry_get_mute, .set_cb = handle_entry_set_mute }
208 enum method_handler_index {
209 METHOD_HANDLER_ADD_ENTRY,
210 METHOD_HANDLER_GET_ENTRY_BY_NAME,
214 enum entry_method_handler_index {
215 ENTRY_METHOD_HANDLER_REMOVE,
216 ENTRY_METHOD_HANDLER_MAX
219 static pa_dbus_arg_info add_entry_args[] = { { "name", "s", "in" },
220 { "device", "s", "in" },
221 { "volume", "a(uu)", "in" },
222 { "mute", "b", "in" },
223 { "entry", "o", "out" } };
224 static pa_dbus_arg_info get_entry_by_name_args[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
226 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
227 [METHOD_HANDLER_ADD_ENTRY] = {
228 .method_name = "AddEntry",
229 .arguments = add_entry_args,
230 .n_arguments = sizeof(add_entry_args) / sizeof(pa_dbus_arg_info),
231 .receive_cb = handle_add_entry },
232 [METHOD_HANDLER_GET_ENTRY_BY_NAME] = {
233 .method_name = "GetEntryByName",
234 .arguments = get_entry_by_name_args,
235 .n_arguments = sizeof(get_entry_by_name_args) / sizeof(pa_dbus_arg_info),
236 .receive_cb = handle_get_entry_by_name }
239 static pa_dbus_method_handler entry_method_handlers[ENTRY_METHOD_HANDLER_MAX] = {
240 [ENTRY_METHOD_HANDLER_REMOVE] = {
241 .method_name = "Remove",
244 .receive_cb = handle_entry_remove }
249 SIGNAL_ENTRY_REMOVED,
253 enum entry_signal_index {
254 ENTRY_SIGNAL_DEVICE_UPDATED,
255 ENTRY_SIGNAL_VOLUME_UPDATED,
256 ENTRY_SIGNAL_MUTE_UPDATED,
260 static pa_dbus_arg_info new_entry_args[] = { { "entry", "o", NULL } };
261 static pa_dbus_arg_info entry_removed_args[] = { { "entry", "o", NULL } };
263 static pa_dbus_arg_info entry_device_updated_args[] = { { "device", "s", NULL } };
264 static pa_dbus_arg_info entry_volume_updated_args[] = { { "volume", "a(uu)", NULL } };
265 static pa_dbus_arg_info entry_mute_updated_args[] = { { "muted", "b", NULL } };
267 static pa_dbus_signal_info signals[SIGNAL_MAX] = {
268 [SIGNAL_NEW_ENTRY] = { .name = "NewEntry", .arguments = new_entry_args, .n_arguments = 1 },
269 [SIGNAL_ENTRY_REMOVED] = { .name = "EntryRemoved", .arguments = entry_removed_args, .n_arguments = 1 }
272 static pa_dbus_signal_info entry_signals[ENTRY_SIGNAL_MAX] = {
273 [ENTRY_SIGNAL_DEVICE_UPDATED] = { .name = "DeviceUpdated", .arguments = entry_device_updated_args, .n_arguments = 1 },
274 [ENTRY_SIGNAL_VOLUME_UPDATED] = { .name = "VolumeUpdated", .arguments = entry_volume_updated_args, .n_arguments = 1 },
275 [ENTRY_SIGNAL_MUTE_UPDATED] = { .name = "MuteUpdated", .arguments = entry_mute_updated_args, .n_arguments = 1 }
278 static pa_dbus_interface_info stream_restore_interface_info = {
279 .name = INTERFACE_STREAM_RESTORE,
280 .method_handlers = method_handlers,
281 .n_method_handlers = METHOD_HANDLER_MAX,
282 .property_handlers = property_handlers,
283 .n_property_handlers = PROPERTY_HANDLER_MAX,
284 .get_all_properties_cb = handle_get_all,
286 .n_signals = SIGNAL_MAX
289 static pa_dbus_interface_info entry_interface_info = {
290 .name = INTERFACE_ENTRY,
291 .method_handlers = entry_method_handlers,
292 .n_method_handlers = ENTRY_METHOD_HANDLER_MAX,
293 .property_handlers = entry_property_handlers,
294 .n_property_handlers = ENTRY_PROPERTY_HANDLER_MAX,
295 .get_all_properties_cb = handle_entry_get_all,
296 .signals = entry_signals,
297 .n_signals = ENTRY_SIGNAL_MAX
300 static struct dbus_entry *dbus_entry_new(struct userdata *u, const char *entry_name) {
301 struct dbus_entry *de;
304 pa_assert(entry_name);
305 pa_assert(*entry_name);
307 de = pa_xnew(struct dbus_entry, 1);
309 de->entry_name = pa_xstrdup(entry_name);
310 de->index = u->next_index++;
311 de->object_path = pa_sprintf_malloc("%s/%s%u", OBJECT_PATH, ENTRY_OBJECT_NAME, de->index);
313 pa_assert_se(pa_dbus_protocol_add_interface(u->dbus_protocol, de->object_path, &entry_interface_info, u) >= 0);
318 static void dbus_entry_free(struct dbus_entry *de) {
321 pa_assert_se(pa_dbus_protocol_remove_interface(de->userdata->dbus_protocol, de->object_path, entry_interface_info.name) >= 0);
323 pa_xfree(de->entry_name);
324 pa_xfree(de->object_path);
327 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
328 * are a channel position and a volume value, respectively. The result is
329 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
330 * element. If the data is invalid, an error reply is sent and a negative
331 * number is returned. In case of a failure we make no guarantees about the
332 * state of map and vol. In case of an empty array the channels field of both
333 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
334 * before returning. */
335 static int get_volume_arg(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, pa_channel_map *map, pa_cvolume *vol) {
336 DBusMessageIter array_iter;
337 DBusMessageIter struct_iter;
342 pa_assert(pa_streq(dbus_message_iter_get_signature(iter), "a(uu)"));
346 pa_channel_map_init(map);
347 pa_cvolume_init(vol);
352 dbus_message_iter_recurse(iter, &array_iter);
354 while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID) {
355 dbus_uint32_t chan_pos;
356 dbus_uint32_t chan_vol;
358 dbus_message_iter_recurse(&array_iter, &struct_iter);
360 dbus_message_iter_get_basic(&struct_iter, &chan_pos);
362 if (chan_pos >= PA_CHANNEL_POSITION_MAX) {
363 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid channel position: %u", chan_pos);
367 pa_assert_se(dbus_message_iter_next(&struct_iter));
368 dbus_message_iter_get_basic(&struct_iter, &chan_vol);
370 if (chan_vol > PA_VOLUME_MAX) {
371 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", chan_vol);
375 if (map->channels < PA_CHANNELS_MAX) {
376 map->map[map->channels] = chan_pos;
377 vol->values[map->channels] = chan_vol;
382 dbus_message_iter_next(&array_iter);
385 if (map->channels > PA_CHANNELS_MAX) {
386 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too many channels: %u. The maximum is %u.", map->channels, PA_CHANNELS_MAX);
390 dbus_message_iter_next(iter);
395 static void append_volume(DBusMessageIter *iter, struct entry *e) {
396 DBusMessageIter array_iter;
397 DBusMessageIter struct_iter;
403 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(uu)", &array_iter));
405 if (!e->volume_valid) {
406 pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
410 for (i = 0; i < e->channel_map.channels; ++i) {
411 pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter));
413 pa_assert_se(dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_UINT32, &e->channel_map.map[i]));
414 pa_assert_se(dbus_message_iter_append_basic(&struct_iter, DBUS_TYPE_UINT32, &e->volume.values[i]));
416 pa_assert_se(dbus_message_iter_close_container(&array_iter, &struct_iter));
419 pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
422 static void append_volume_variant(DBusMessageIter *iter, struct entry *e) {
423 DBusMessageIter variant_iter;
428 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(uu)", &variant_iter));
430 append_volume(&variant_iter, e);
432 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
435 static void send_new_entry_signal(struct dbus_entry *entry) {
436 DBusMessage *signal_msg;
440 pa_assert_se(signal_msg = dbus_message_new_signal(OBJECT_PATH, INTERFACE_STREAM_RESTORE, signals[SIGNAL_NEW_ENTRY].name));
441 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &entry->object_path, DBUS_TYPE_INVALID));
442 pa_dbus_protocol_send_signal(entry->userdata->dbus_protocol, signal_msg);
443 dbus_message_unref(signal_msg);
446 static void send_entry_removed_signal(struct dbus_entry *entry) {
447 DBusMessage *signal_msg;
451 pa_assert_se(signal_msg = dbus_message_new_signal(OBJECT_PATH, INTERFACE_STREAM_RESTORE, signals[SIGNAL_ENTRY_REMOVED].name));
452 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &entry->object_path, DBUS_TYPE_INVALID));
453 pa_dbus_protocol_send_signal(entry->userdata->dbus_protocol, signal_msg);
454 dbus_message_unref(signal_msg);
457 static void send_device_updated_signal(struct dbus_entry *de, struct entry *e) {
458 DBusMessage *signal_msg;
464 device = e->device_valid ? e->device : "";
466 pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_DEVICE_UPDATED].name));
467 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID));
468 pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg);
469 dbus_message_unref(signal_msg);
472 static void send_volume_updated_signal(struct dbus_entry *de, struct entry *e) {
473 DBusMessage *signal_msg;
474 DBusMessageIter msg_iter;
479 pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_VOLUME_UPDATED].name));
480 dbus_message_iter_init_append(signal_msg, &msg_iter);
481 append_volume(&msg_iter, e);
482 pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg);
483 dbus_message_unref(signal_msg);
486 static void send_mute_updated_signal(struct dbus_entry *de, struct entry *e) {
487 DBusMessage *signal_msg;
493 pa_assert(e->muted_valid);
497 pa_assert_se(signal_msg = dbus_message_new_signal(de->object_path, INTERFACE_ENTRY, entry_signals[ENTRY_SIGNAL_MUTE_UPDATED].name));
498 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &muted, DBUS_TYPE_INVALID));
499 pa_dbus_protocol_send_signal(de->userdata->dbus_protocol, signal_msg);
500 dbus_message_unref(signal_msg);
503 static void handle_get_interface_revision(DBusConnection *conn, DBusMessage *msg, void *userdata) {
504 dbus_uint32_t interface_revision = DBUS_INTERFACE_REVISION;
509 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &interface_revision);
512 /* The caller frees the array, but not the strings. */
513 static const char **get_entries(struct userdata *u, unsigned *n) {
514 const char **entries;
517 struct dbus_entry *de;
522 *n = pa_hashmap_size(u->dbus_entries);
527 entries = pa_xnew(const char *, *n);
529 PA_HASHMAP_FOREACH(de, u->dbus_entries, state)
530 entries[i++] = de->object_path;
535 static void handle_get_entries(DBusConnection *conn, DBusMessage *msg, void *userdata) {
536 struct userdata *u = userdata;
537 const char **entries;
544 entries = get_entries(u, &n);
546 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, entries, n);
551 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
552 struct userdata *u = userdata;
553 DBusMessage *reply = NULL;
554 DBusMessageIter msg_iter;
555 DBusMessageIter dict_iter;
556 dbus_uint32_t interface_revision;
557 const char **entries;
564 interface_revision = DBUS_INTERFACE_REVISION;
565 entries = get_entries(u, &n_entries);
567 pa_assert_se((reply = dbus_message_new_method_return(msg)));
569 dbus_message_iter_init_append(reply, &msg_iter);
570 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
572 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INTERFACE_REVISION].property_name, DBUS_TYPE_UINT32, &interface_revision);
573 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ENTRIES].property_name, DBUS_TYPE_OBJECT_PATH, entries, n_entries);
575 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
577 pa_assert_se(dbus_connection_send(conn, reply, NULL));
579 dbus_message_unref(reply);
584 static void handle_add_entry(DBusConnection *conn, DBusMessage *msg, void *userdata) {
585 struct userdata *u = userdata;
586 DBusMessageIter msg_iter;
587 const char *name = NULL;
588 const char *device = NULL;
591 dbus_bool_t muted = FALSE;
592 dbus_bool_t apply_immediately = FALSE;
595 struct dbus_entry *dbus_entry = NULL;
596 struct entry *e = NULL;
602 pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
603 dbus_message_iter_get_basic(&msg_iter, &name);
605 pa_assert_se(dbus_message_iter_next(&msg_iter));
606 dbus_message_iter_get_basic(&msg_iter, &device);
608 pa_assert_se(dbus_message_iter_next(&msg_iter));
609 if (get_volume_arg(conn, msg, &msg_iter, &map, &vol) < 0)
612 dbus_message_iter_get_basic(&msg_iter, &muted);
614 pa_assert_se(dbus_message_iter_next(&msg_iter));
615 dbus_message_iter_get_basic(&msg_iter, &apply_immediately);
618 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "An empty string was given as the entry name.");
622 if ((dbus_entry = pa_hashmap_get(u->dbus_entries, name))) {
623 pa_bool_t mute_updated = FALSE;
624 pa_bool_t volume_updated = FALSE;
625 pa_bool_t device_updated = FALSE;
627 pa_assert_se(e = read_entry(u, name));
628 mute_updated = e->muted != muted;
630 e->muted_valid = TRUE;
632 volume_updated = (e->volume_valid != !!map.channels) || !pa_cvolume_equal(&e->volume, &vol);
634 e->channel_map = map;
635 e->volume_valid = !!map.channels;
637 device_updated = (e->device_valid != !!device[0]) || !pa_streq(e->device, device);
638 pa_strlcpy(e->device, device, sizeof(e->device));
639 e->device_valid = !!device[0];
642 send_mute_updated_signal(dbus_entry, e);
644 send_volume_updated_signal(dbus_entry, e);
646 send_device_updated_signal(dbus_entry, e);
649 dbus_entry = dbus_entry_new(u, name);
650 pa_assert_se(pa_hashmap_put(u->dbus_entries, dbus_entry->entry_name, dbus_entry) == 0);
652 e = pa_xnew0(struct entry, 1);
653 e->muted_valid = TRUE;
654 e->volume_valid = !!map.channels;
655 e->device_valid = !!device[0];
658 e->channel_map = map;
659 pa_strlcpy(e->device, device, sizeof(e->device));
661 send_new_entry_signal(dbus_entry);
664 key.data = (char *) name;
665 key.size = strlen(name);
668 value.size = sizeof(struct entry);
670 pa_assert_se(pa_database_set(u->database, &key, &value, TRUE) == 0);
671 if (apply_immediately)
672 apply_entry(u, name, e);
676 pa_dbus_send_empty_reply(conn, msg);
681 static void handle_get_entry_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
682 struct userdata *u = userdata;
684 struct dbus_entry *de;
690 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
692 if (!(de = pa_hashmap_get(u->dbus_entries, name))) {
693 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such stream restore entry.");
697 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &de->object_path);
700 static void handle_entry_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
701 struct dbus_entry *de = userdata;
707 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &de->index);
710 static void handle_entry_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
711 struct dbus_entry *de = userdata;
717 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &de->entry_name);
720 static void handle_entry_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
721 struct dbus_entry *de = userdata;
729 pa_assert_se(e = read_entry(de->userdata, de->entry_name));
731 device = e->device_valid ? e->device : "";
733 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &device);
738 static void handle_entry_set_device(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
739 struct dbus_entry *de = userdata;
749 dbus_message_iter_get_basic(iter, &device);
751 pa_assert_se(e = read_entry(de->userdata, de->entry_name));
753 updated = (e->device_valid != !!device[0]) || !pa_streq(e->device, device);
759 pa_strlcpy(e->device, device, sizeof(e->device));
760 e->device_valid = !!device[0];
762 key.data = de->entry_name;
763 key.size = strlen(de->entry_name);
765 value.size = sizeof(struct entry);
766 pa_assert_se(pa_database_set(de->userdata->database, &key, &value, TRUE) == 0);
768 send_device_updated_signal(de, e);
769 trigger_save(de->userdata);
772 pa_dbus_send_empty_reply(conn, msg);
777 static void handle_entry_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
778 struct dbus_entry *de = userdata;
780 DBusMessageIter msg_iter;
787 pa_assert_se(e = read_entry(de->userdata, de->entry_name));
789 pa_assert_se(reply = dbus_message_new_method_return(msg));
791 dbus_message_iter_init_append(reply, &msg_iter);
792 append_volume_variant(&msg_iter, e);
794 pa_assert_se(dbus_connection_send(conn, reply, NULL));
799 static void handle_entry_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
800 struct dbus_entry *de = userdata;
803 struct entry *e = NULL;
804 pa_bool_t updated = FALSE;
811 if (get_volume_arg(conn, msg, iter, &map, &vol) < 0)
814 pa_assert_se(e = read_entry(de->userdata, de->entry_name));
816 updated = (e->volume_valid != !!map.channels) || !pa_cvolume_equal(&e->volume, &vol);
823 e->channel_map = map;
824 e->volume_valid = !!map.channels;
826 key.data = de->entry_name;
827 key.size = strlen(de->entry_name);
829 value.size = sizeof(struct entry);
830 pa_assert_se(pa_database_set(de->userdata->database, &key, &value, TRUE) == 0);
832 send_volume_updated_signal(de, e);
833 trigger_save(de->userdata);
836 pa_dbus_send_empty_reply(conn, msg);
841 static void handle_entry_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
842 struct dbus_entry *de = userdata;
850 pa_assert_se(e = read_entry(de->userdata, de->entry_name));
852 mute = e->muted_valid ? e->muted : FALSE;
854 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &mute);
859 static void handle_entry_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
860 struct dbus_entry *de = userdata;
870 dbus_message_iter_get_basic(iter, &mute);
872 pa_assert_se(e = read_entry(de->userdata, de->entry_name));
874 updated = !e->muted_valid || e->muted != mute;
881 e->muted_valid = TRUE;
883 key.data = de->entry_name;
884 key.size = strlen(de->entry_name);
886 value.size = sizeof(struct entry);
887 pa_assert_se(pa_database_set(de->userdata->database, &key, &value, TRUE) == 0);
889 send_mute_updated_signal(de, e);
890 trigger_save(de->userdata);
893 pa_dbus_send_empty_reply(conn, msg);
898 static void handle_entry_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
899 struct dbus_entry *de = userdata;
901 DBusMessage *reply = NULL;
902 DBusMessageIter msg_iter;
903 DBusMessageIter dict_iter;
904 DBusMessageIter dict_entry_iter;
912 pa_assert_se(e = read_entry(de->userdata, de->entry_name));
914 device = e->device_valid ? e->device : "";
915 mute = e->muted_valid ? e->muted : FALSE;
917 pa_assert_se((reply = dbus_message_new_method_return(msg)));
919 dbus_message_iter_init_append(reply, &msg_iter);
920 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
922 pa_dbus_append_basic_variant_dict_entry(&dict_iter, entry_property_handlers[ENTRY_PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &de->index);
923 pa_dbus_append_basic_variant_dict_entry(&dict_iter, entry_property_handlers[ENTRY_PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &de->entry_name);
924 pa_dbus_append_basic_variant_dict_entry(&dict_iter, entry_property_handlers[ENTRY_PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_STRING, &device);
926 pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
928 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &entry_property_handlers[ENTRY_PROPERTY_HANDLER_VOLUME].property_name));
929 append_volume_variant(&dict_entry_iter, e);
931 pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
933 pa_dbus_append_basic_variant_dict_entry(&dict_iter, entry_property_handlers[ENTRY_PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &mute);
935 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
937 pa_assert_se(dbus_connection_send(conn, reply, NULL));
939 dbus_message_unref(reply);
944 static void handle_entry_remove(DBusConnection *conn, DBusMessage *msg, void *userdata) {
945 struct dbus_entry *de = userdata;
952 key.data = de->entry_name;
953 key.size = strlen(de->entry_name);
955 pa_assert_se(pa_database_unset(de->userdata->database, &key) == 0);
957 send_entry_removed_signal(de);
958 trigger_save(de->userdata);
960 pa_assert_se(pa_hashmap_remove(de->userdata->dbus_entries, de->entry_name));
963 pa_dbus_send_empty_reply(conn, msg);
966 #endif /* HAVE_DBUS */
968 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
969 struct userdata *u = userdata;
975 pa_assert(e == u->save_time_event);
976 u->core->mainloop->time_free(u->save_time_event);
977 u->save_time_event = NULL;
979 pa_database_sync(u->database);
980 pa_log_info("Synced.");
983 static char *get_name(pa_proplist *p, const char *prefix) {
990 if ((r = pa_proplist_gets(p, IDENTIFICATION_PROPERTY)))
991 return pa_xstrdup(r);
993 if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_ROLE)))
994 t = pa_sprintf_malloc("%s-by-media-role:%s", prefix, r);
995 else if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_ID)))
996 t = pa_sprintf_malloc("%s-by-application-id:%s", prefix, r);
997 else if ((r = pa_proplist_gets(p, PA_PROP_APPLICATION_NAME)))
998 t = pa_sprintf_malloc("%s-by-application-name:%s", prefix, r);
999 else if ((r = pa_proplist_gets(p, PA_PROP_MEDIA_NAME)))
1000 t = pa_sprintf_malloc("%s-by-media-name:%s", prefix, r);
1002 t = pa_sprintf_malloc("%s-fallback:%s", prefix, r);
1004 pa_proplist_sets(p, IDENTIFICATION_PROPERTY, t);
1008 static struct entry *read_entry(struct userdata *u, const char *name) {
1015 key.data = (char*) name;
1016 key.size = strlen(name);
1020 if (!pa_database_get(u->database, &key, &data))
1023 if (data.size != sizeof(struct entry)) {
1024 /* This is probably just a database upgrade, hence let's not
1025 * consider this more than a debug message */
1026 pa_log_debug("Database contains entry for stream %s of wrong size %lu != %lu. Probably due to uprade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry));
1030 e = (struct entry*) data.data;
1032 if (e->version != ENTRY_VERSION) {
1033 pa_log_debug("Version of database entry for stream %s doesn't match our version. Probably due to upgrade, ignoring.", name);
1037 if (!memchr(e->device, 0, sizeof(e->device))) {
1038 pa_log_warn("Database contains entry for stream %s with missing NUL byte in device name", name);
1042 if (!memchr(e->card, 0, sizeof(e->card))) {
1043 pa_log_warn("Database contains entry for stream %s with missing NUL byte in card name", name);
1047 if (e->device_valid && !pa_namereg_is_valid_name(e->device)) {
1048 pa_log_warn("Invalid device name stored in database for stream %s", name);
1052 if (e->card_valid && !pa_namereg_is_valid_name(e->card)) {
1053 pa_log_warn("Invalid card name stored in database for stream %s", name);
1057 if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
1058 pa_log_warn("Invalid channel map stored in database for stream %s", name);
1062 if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
1063 pa_log_warn("Invalid volume stored in database for stream %s", name);
1071 pa_datum_free(&data);
1075 static void trigger_save(struct userdata *u) {
1076 pa_native_connection *c;
1079 for (c = pa_idxset_first(u->subscribed, &idx); c; c = pa_idxset_next(u->subscribed, &idx)) {
1082 t = pa_tagstruct_new(NULL, 0);
1083 pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
1084 pa_tagstruct_putu32(t, 0);
1085 pa_tagstruct_putu32(t, u->module->index);
1086 pa_tagstruct_puts(t, u->module->name);
1087 pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
1089 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
1092 if (u->save_time_event)
1095 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
1098 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
1104 if (a->device_valid != b->device_valid ||
1105 (a->device_valid && strncmp(a->device, b->device, sizeof(a->device))))
1108 if (a->card_valid != b->card_valid ||
1109 (a->card_valid && strncmp(a->card, b->card, sizeof(a->card))))
1112 if (a->muted_valid != b->muted_valid ||
1113 (a->muted_valid && (a->muted != b->muted)))
1117 if (a->volume_valid != b->volume_valid ||
1118 (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
1124 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
1125 struct userdata *u = userdata;
1126 struct entry entry, *old = NULL;
1130 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1131 * clutter these are defined here unconditionally. */
1132 pa_bool_t created_new_entry = TRUE;
1133 pa_bool_t device_updated = FALSE;
1134 pa_bool_t volume_updated = FALSE;
1135 pa_bool_t mute_updated = FALSE;
1138 struct dbus_entry *de = NULL;
1144 if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
1145 t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
1146 t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
1147 t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE))
1151 entry.version = ENTRY_VERSION;
1153 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
1154 pa_sink_input *sink_input;
1156 if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx)))
1159 if (!(name = get_name(sink_input->proplist, "sink-input")))
1162 if ((old = read_entry(u, name))) {
1164 created_new_entry = FALSE;
1167 if (sink_input->save_volume) {
1168 entry.channel_map = sink_input->channel_map;
1169 pa_sink_input_get_volume(sink_input, &entry.volume, FALSE);
1170 entry.volume_valid = TRUE;
1172 volume_updated = !created_new_entry
1173 && (!old->volume_valid
1174 || !pa_channel_map_equal(&entry.channel_map, &old->channel_map)
1175 || !pa_cvolume_equal(&entry.volume, &old->volume));
1178 if (sink_input->save_muted) {
1179 entry.muted = pa_sink_input_get_mute(sink_input);
1180 entry.muted_valid = TRUE;
1182 mute_updated = !created_new_entry && (!old->muted_valid || entry.muted != old->muted);
1185 if (sink_input->save_sink) {
1186 pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device));
1187 entry.device_valid = TRUE;
1189 device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry.device, old->device));
1190 if (sink_input->sink->card) {
1191 pa_strlcpy(entry.card, sink_input->sink->card->name, sizeof(entry.card));
1192 entry.card_valid = TRUE;
1197 pa_source_output *source_output;
1199 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT);
1201 if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx)))
1204 if (!(name = get_name(source_output->proplist, "source-output")))
1207 if ((old = read_entry(u, name))) {
1209 created_new_entry = FALSE;
1212 if (source_output->save_source) {
1213 pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device));
1214 entry.device_valid = source_output->save_source;
1216 device_updated = !created_new_entry && (!old->device_valid || !pa_streq(entry.device, old->device));
1218 if (source_output->source->card) {
1219 pa_strlcpy(entry.card, source_output->source->card->name, sizeof(entry.card));
1220 entry.card_valid = TRUE;
1227 if (entries_equal(old, &entry)) {
1237 key.size = strlen(name);
1240 data.size = sizeof(entry);
1242 pa_log_info("Storing volume/mute/device for stream %s.", name);
1244 pa_database_set(u->database, &key, &data, TRUE);
1247 if (created_new_entry) {
1248 de = dbus_entry_new(u, name);
1249 pa_assert_se(pa_hashmap_put(u->dbus_entries, de->entry_name, de) == 0);
1250 send_new_entry_signal(de);
1252 pa_assert_se(de = pa_hashmap_get(u->dbus_entries, name));
1255 send_device_updated_signal(de, &entry);
1257 send_volume_updated_signal(de, &entry);
1259 send_mute_updated_signal(de, &entry);
1268 static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
1273 pa_assert(new_data);
1275 pa_assert(u->restore_device);
1277 if (!(name = get_name(new_data->proplist, "sink-input")))
1281 pa_log_debug("Not restoring device for stream %s, because already set.", name);
1282 else if ((e = read_entry(u, name))) {
1285 if (e->device_valid)
1286 s = pa_namereg_get(c, e->device, PA_NAMEREG_SINK);
1288 if (!s && e->card_valid) {
1291 if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD)))
1292 s = pa_idxset_first(card->sinks, NULL);
1295 /* It might happen that a stream and a sink are set up at the
1296 same time, in which case we want to make sure we don't
1297 interfere with that */
1298 if (s && PA_SINK_IS_LINKED(pa_sink_get_state(s))) {
1299 pa_log_info("Restoring device for stream %s.", name);
1301 new_data->save_sink = TRUE;
1312 static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
1317 pa_assert(new_data);
1319 pa_assert(u->restore_volume || u->restore_muted);
1321 if (!(name = get_name(new_data->proplist, "sink-input")))
1324 if ((e = read_entry(u, name))) {
1326 if (u->restore_volume && e->volume_valid) {
1328 if (!new_data->volume_is_set) {
1331 pa_log_info("Restoring volume for sink input %s.", name);
1334 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
1335 pa_sink_input_new_data_set_volume(new_data, &v);
1337 new_data->volume_is_absolute = FALSE;
1338 new_data->save_volume = TRUE;
1340 pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
1343 if (u->restore_muted && e->muted_valid) {
1345 if (!new_data->muted_is_set) {
1346 pa_log_info("Restoring mute state for sink input %s.", name);
1347 pa_sink_input_new_data_set_muted(new_data, e->muted);
1348 new_data->save_muted = TRUE;
1350 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name);
1361 static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
1366 pa_assert(new_data);
1368 pa_assert(u->restore_device);
1370 if (new_data->direct_on_input)
1373 if (!(name = get_name(new_data->proplist, "source-output")))
1376 if (new_data->source)
1377 pa_log_debug("Not restoring device for stream %s, because already set", name);
1378 else if ((e = read_entry(u, name))) {
1379 pa_source *s = NULL;
1381 if (e->device_valid)
1382 s = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE);
1384 if (!s && e->card_valid) {
1387 if ((card = pa_namereg_get(c, e->card, PA_NAMEREG_CARD)))
1388 s = pa_idxset_first(card->sources, NULL);
1391 /* It might happen that a stream and a sink are set up at the
1392 same time, in which case we want to make sure we don't
1393 interfere with that */
1394 if (s && PA_SOURCE_IS_LINKED(pa_source_get_state(s))) {
1395 pa_log_info("Restoring device for stream %s.", name);
1396 new_data->source = s;
1397 new_data->save_source = TRUE;
1408 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
1415 pa_assert(u->on_hotplug && u->restore_device);
1417 PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
1421 if (si->sink == sink)
1427 /* Skip this if it is already in the process of being moved
1432 /* It might happen that a stream and a sink are set up at the
1433 same time, in which case we want to make sure we don't
1434 interfere with that */
1435 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si)))
1438 if (!(name = get_name(si->proplist, "sink-input")))
1441 if ((e = read_entry(u, name))) {
1442 if (e->device_valid && pa_streq(e->device, sink->name))
1443 pa_sink_input_move_to(si, sink, TRUE);
1454 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
1455 pa_source_output *so;
1461 pa_assert(u->on_hotplug && u->restore_device);
1463 PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
1467 if (so->source == source)
1470 if (so->save_source)
1473 if (so->direct_on_input)
1476 /* Skip this if it is already in the process of being moved anyway */
1480 /* It might happen that a stream and a source are set up at the
1481 same time, in which case we want to make sure we don't
1482 interfere with that */
1483 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so)))
1486 if (!(name = get_name(so->proplist, "source-input")))
1489 if ((e = read_entry(u, name))) {
1490 if (e->device_valid && pa_streq(e->device, source->name))
1491 pa_source_output_move_to(so, source, TRUE);
1502 static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
1509 pa_assert(u->on_rescue && u->restore_device);
1511 /* There's no point in doing anything if the core is shut down anyway */
1512 if (c->state == PA_CORE_SHUTDOWN)
1515 PA_IDXSET_FOREACH(si, sink->inputs, idx) {
1522 if (!(name = get_name(si->proplist, "sink-input")))
1525 if ((e = read_entry(u, name))) {
1527 if (e->device_valid) {
1530 if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) &&
1532 PA_SINK_IS_LINKED(pa_sink_get_state(d)))
1533 pa_sink_input_move_to(si, d, TRUE);
1545 static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
1546 pa_source_output *so;
1552 pa_assert(u->on_rescue && u->restore_device);
1554 /* There's no point in doing anything if the core is shut down anyway */
1555 if (c->state == PA_CORE_SHUTDOWN)
1558 PA_IDXSET_FOREACH(so, source->outputs, idx) {
1562 if (so->direct_on_input)
1568 if (!(name = get_name(so->proplist, "source-output")))
1571 if ((e = read_entry(u, name))) {
1573 if (e->device_valid) {
1576 if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) &&
1578 PA_SOURCE_IS_LINKED(pa_source_get_state(d)))
1579 pa_source_output_move_to(so, d, TRUE);
1591 #define EXT_VERSION 1
1593 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
1595 pa_source_output *so;
1602 PA_IDXSET_FOREACH(si, u->core->sink_inputs, idx) {
1606 if (!(n = get_name(si->proplist, "sink-input")))
1609 if (!pa_streq(name, n)) {
1615 if (u->restore_volume && e->volume_valid) {
1619 pa_log_info("Restoring volume for sink input %s.", name);
1620 pa_cvolume_remap(&v, &e->channel_map, &si->channel_map);
1621 pa_sink_input_set_volume(si, &v, TRUE, FALSE);
1624 if (u->restore_muted && e->muted_valid) {
1625 pa_log_info("Restoring mute state for sink input %s.", name);
1626 pa_sink_input_set_mute(si, e->muted, TRUE);
1629 if (u->restore_device &&
1631 (s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SINK))) {
1633 pa_log_info("Restoring device for stream %s.", name);
1634 pa_sink_input_move_to(si, s, TRUE);
1638 PA_IDXSET_FOREACH(so, u->core->source_outputs, idx) {
1642 if (!(n = get_name(so->proplist, "source-output")))
1645 if (!pa_streq(name, n)) {
1651 if (u->restore_device &&
1653 (s = pa_namereg_get(u->core, e->device, PA_NAMEREG_SOURCE))) {
1655 pa_log_info("Restoring device for stream %s.", name);
1656 pa_source_output_move_to(so, s, TRUE);
1662 static void dump_database(struct userdata *u) {
1666 done = !pa_database_first(u->database, &key, NULL);
1673 done = !pa_database_next(u->database, &key, &next_key, NULL);
1675 name = pa_xstrndup(key.data, key.size);
1676 pa_datum_free(&key);
1678 if ((e = read_entry(u, name))) {
1680 pa_log("name=%s", name);
1681 pa_log("device=%s %s", e->device, pa_yes_no(e->device_valid));
1682 pa_log("channel_map=%s", pa_channel_map_snprint(t, sizeof(t), &e->channel_map));
1683 pa_log("volume=%s %s", pa_cvolume_snprint(t, sizeof(t), &e->volume), pa_yes_no(e->volume_valid));
1684 pa_log("mute=%s %s", pa_yes_no(e->muted), pa_yes_no(e->volume_valid));
1695 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
1698 pa_tagstruct *reply = NULL;
1707 if (pa_tagstruct_getu32(t, &command) < 0)
1710 reply = pa_tagstruct_new(NULL, 0);
1711 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1712 pa_tagstruct_putu32(reply, tag);
1715 case SUBCOMMAND_TEST: {
1716 if (!pa_tagstruct_eof(t))
1719 pa_tagstruct_putu32(reply, EXT_VERSION);
1723 case SUBCOMMAND_READ: {
1727 if (!pa_tagstruct_eof(t))
1730 done = !pa_database_first(u->database, &key, NULL);
1737 done = !pa_database_next(u->database, &key, &next_key, NULL);
1739 name = pa_xstrndup(key.data, key.size);
1740 pa_datum_free(&key);
1742 if ((e = read_entry(u, name))) {
1746 pa_tagstruct_puts(reply, name);
1747 pa_tagstruct_put_channel_map(reply, e->volume_valid ? &e->channel_map : pa_channel_map_init(&cm));
1748 pa_tagstruct_put_cvolume(reply, e->volume_valid ? &e->volume : pa_cvolume_init(&r));
1749 pa_tagstruct_puts(reply, e->device_valid ? e->device : NULL);
1750 pa_tagstruct_put_boolean(reply, e->muted_valid ? e->muted : FALSE);
1763 case SUBCOMMAND_WRITE: {
1765 pa_bool_t apply_immediately = FALSE;
1767 if (pa_tagstruct_getu32(t, &mode) < 0 ||
1768 pa_tagstruct_get_boolean(t, &apply_immediately) < 0)
1771 if (mode != PA_UPDATE_MERGE &&
1772 mode != PA_UPDATE_REPLACE &&
1773 mode != PA_UPDATE_SET)
1776 if (mode == PA_UPDATE_SET) {
1778 struct dbus_entry *de;
1781 PA_HASHMAP_FOREACH(de, u->dbus_entries, state) {
1782 send_entry_removed_signal(de);
1783 dbus_entry_free(pa_hashmap_remove(u->dbus_entries, de->entry_name));
1786 pa_database_clear(u->database);
1789 while (!pa_tagstruct_eof(t)) {
1790 const char *name, *device;
1799 entry.version = ENTRY_VERSION;
1801 if (pa_tagstruct_gets(t, &name) < 0 ||
1802 pa_tagstruct_get_channel_map(t, &entry.channel_map) ||
1803 pa_tagstruct_get_cvolume(t, &entry.volume) < 0 ||
1804 pa_tagstruct_gets(t, &device) < 0 ||
1805 pa_tagstruct_get_boolean(t, &muted) < 0)
1808 if (!name || !*name)
1811 entry.volume_valid = entry.volume.channels > 0;
1813 if (entry.volume_valid)
1814 if (!pa_cvolume_compatible_with_channel_map(&entry.volume, &entry.channel_map))
1817 entry.muted = muted;
1818 entry.muted_valid = TRUE;
1821 pa_strlcpy(entry.device, device, sizeof(entry.device));
1822 entry.device_valid = !!entry.device[0];
1824 if (entry.device_valid &&
1825 !pa_namereg_is_valid_name(entry.device))
1829 old = read_entry(u, name);
1832 key.data = (char*) name;
1833 key.size = strlen(name);
1836 data.size = sizeof(entry);
1838 pa_log_debug("Client %s changes entry %s.",
1839 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c)->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)),
1842 if (pa_database_set(u->database, &key, &data, mode == PA_UPDATE_REPLACE) == 0) {
1844 struct dbus_entry *de;
1847 pa_assert_se((de = pa_hashmap_get(u->dbus_entries, name)));
1849 if ((old->device_valid != entry.device_valid)
1850 || (entry.device_valid && !pa_streq(entry.device, old->device)))
1851 send_device_updated_signal(de, &entry);
1853 if ((old->volume_valid != entry.volume_valid)
1854 || (entry.volume_valid && (!pa_cvolume_equal(&entry.volume, &old->volume)
1855 || !pa_channel_map_equal(&entry.channel_map, &old->channel_map))))
1856 send_volume_updated_signal(de, &entry);
1858 if (!old->muted_valid || (entry.muted != old->muted))
1859 send_mute_updated_signal(de, &entry);
1862 de = dbus_entry_new(u, name);
1863 pa_assert_se(pa_hashmap_put(u->dbus_entries, de->entry_name, de) == 0);
1864 send_new_entry_signal(de);
1868 if (apply_immediately)
1869 apply_entry(u, name, &entry);
1883 case SUBCOMMAND_DELETE:
1885 while (!pa_tagstruct_eof(t)) {
1889 struct dbus_entry *de;
1892 if (pa_tagstruct_gets(t, &name) < 0)
1896 if ((de = pa_hashmap_get(u->dbus_entries, name))) {
1897 send_entry_removed_signal(de);
1898 dbus_entry_free(pa_hashmap_remove(u->dbus_entries, name));
1902 key.data = (char*) name;
1903 key.size = strlen(name);
1905 pa_database_unset(u->database, &key);
1912 case SUBCOMMAND_SUBSCRIBE: {
1916 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1917 !pa_tagstruct_eof(t))
1921 pa_idxset_put(u->subscribed, c, NULL);
1923 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1932 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1938 pa_tagstruct_free(reply);
1943 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
1948 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1952 int pa__init(pa_module*m) {
1953 pa_modargs *ma = NULL;
1957 pa_source_output *so;
1959 pa_bool_t restore_device = TRUE, restore_volume = TRUE, restore_muted = TRUE, on_hotplug = TRUE, on_rescue = TRUE;
1967 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1968 pa_log("Failed to parse module arguments");
1972 if (pa_modargs_get_value_boolean(ma, "restore_device", &restore_device) < 0 ||
1973 pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
1974 pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
1975 pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
1976 pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
1977 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
1981 if (!restore_muted && !restore_volume && !restore_device)
1982 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
1984 m->userdata = u = pa_xnew0(struct userdata, 1);
1987 u->restore_device = restore_device;
1988 u->restore_volume = restore_volume;
1989 u->restore_muted = restore_muted;
1990 u->on_hotplug = on_hotplug;
1991 u->on_rescue = on_rescue;
1992 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1994 u->protocol = pa_native_protocol_get(m->core);
1995 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1997 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);
1999 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
2001 if (restore_device) {
2002 /* A little bit earlier than module-intended-roles ... */
2003 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);
2004 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);
2007 if (restore_device && on_hotplug) {
2008 /* A little bit earlier than module-intended-roles ... */
2009 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);
2010 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);
2013 if (restore_device && on_rescue) {
2014 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2015 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);
2016 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);
2019 if (restore_volume || restore_muted)
2020 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);
2022 if (!(fname = pa_state_path("stream-volumes", TRUE)))
2025 if (!(u->database = pa_database_open(fname, TRUE))) {
2026 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
2031 pa_log_info("Sucessfully opened database file '%s'.", fname);
2035 u->dbus_protocol = pa_dbus_protocol_get(u->core);
2036 u->dbus_entries = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2038 pa_assert_se(pa_dbus_protocol_add_interface(u->dbus_protocol, OBJECT_PATH, &stream_restore_interface_info, u) >= 0);
2039 pa_assert_se(pa_dbus_protocol_register_extension(u->dbus_protocol, INTERFACE_STREAM_RESTORE) >= 0);
2041 /* Create the initial dbus entries. */
2042 done = !pa_database_first(u->database, &key, NULL);
2046 struct dbus_entry *de;
2049 done = !pa_database_next(u->database, &key, &next_key, NULL);
2051 name = pa_xstrndup(key.data, key.size);
2052 pa_datum_free(&key);
2054 /* Use read_entry() for checking that the entry is valid. */
2055 if ((e = read_entry(u, name))) {
2056 de = dbus_entry_new(u, name);
2057 pa_assert_se(pa_hashmap_put(u->dbus_entries, de->entry_name, de) == 0);
2067 PA_IDXSET_FOREACH(si, m->core->sink_inputs, idx)
2068 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, si->index, u);
2070 PA_IDXSET_FOREACH(so, m->core->source_outputs, idx)
2071 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, so->index, u);
2073 pa_modargs_free(ma);
2080 pa_modargs_free(ma);
2086 static void free_dbus_entry_cb(void *p, void *userdata) {
2087 struct dbus_entry *de = p;
2091 dbus_entry_free(de);
2095 void pa__done(pa_module*m) {
2100 if (!(u = m->userdata))
2104 if (u->dbus_protocol) {
2105 pa_assert(u->dbus_entries);
2107 pa_assert_se(pa_dbus_protocol_unregister_extension(u->dbus_protocol, INTERFACE_STREAM_RESTORE) >= 0);
2108 pa_assert_se(pa_dbus_protocol_remove_interface(u->dbus_protocol, OBJECT_PATH, stream_restore_interface_info.name) >= 0);
2110 pa_hashmap_free(u->dbus_entries, free_dbus_entry_cb, NULL);
2112 pa_dbus_protocol_unref(u->dbus_protocol);
2116 if (u->subscription)
2117 pa_subscription_free(u->subscription);
2119 if (u->sink_input_new_hook_slot)
2120 pa_hook_slot_free(u->sink_input_new_hook_slot);
2121 if (u->sink_input_fixate_hook_slot)
2122 pa_hook_slot_free(u->sink_input_fixate_hook_slot);
2123 if (u->source_output_new_hook_slot)
2124 pa_hook_slot_free(u->source_output_new_hook_slot);
2126 if (u->sink_put_hook_slot)
2127 pa_hook_slot_free(u->sink_put_hook_slot);
2128 if (u->source_put_hook_slot)
2129 pa_hook_slot_free(u->source_put_hook_slot);
2131 if (u->sink_unlink_hook_slot)
2132 pa_hook_slot_free(u->sink_unlink_hook_slot);
2133 if (u->source_unlink_hook_slot)
2134 pa_hook_slot_free(u->source_unlink_hook_slot);
2136 if (u->connection_unlink_hook_slot)
2137 pa_hook_slot_free(u->connection_unlink_hook_slot);
2139 if (u->save_time_event)
2140 u->core->mainloop->time_free(u->save_time_event);
2143 pa_database_close(u->database);
2146 pa_native_protocol_remove_ext(u->protocol, m);
2147 pa_native_protocol_unref(u->protocol);
2151 pa_idxset_free(u->subscribed, NULL, NULL);