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 { "apply_immediately", "b", "in" },
238 { "entry", "o", "out" } };
239 static pa_dbus_arg_info get_entry_by_name_args
[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
241 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
242 [METHOD_HANDLER_ADD_ENTRY
] = {
243 .method_name
= "AddEntry",
244 .arguments
= add_entry_args
,
245 .n_arguments
= sizeof(add_entry_args
) / sizeof(pa_dbus_arg_info
),
246 .receive_cb
= handle_add_entry
},
247 [METHOD_HANDLER_GET_ENTRY_BY_NAME
] = {
248 .method_name
= "GetEntryByName",
249 .arguments
= get_entry_by_name_args
,
250 .n_arguments
= sizeof(get_entry_by_name_args
) / sizeof(pa_dbus_arg_info
),
251 .receive_cb
= handle_get_entry_by_name
}
254 static pa_dbus_method_handler entry_method_handlers
[ENTRY_METHOD_HANDLER_MAX
] = {
255 [ENTRY_METHOD_HANDLER_REMOVE
] = {
256 .method_name
= "Remove",
259 .receive_cb
= handle_entry_remove
}
264 SIGNAL_ENTRY_REMOVED
,
268 enum entry_signal_index
{
269 ENTRY_SIGNAL_DEVICE_UPDATED
,
270 ENTRY_SIGNAL_VOLUME_UPDATED
,
271 ENTRY_SIGNAL_MUTE_UPDATED
,
275 static pa_dbus_arg_info new_entry_args
[] = { { "entry", "o", NULL
} };
276 static pa_dbus_arg_info entry_removed_args
[] = { { "entry", "o", NULL
} };
278 static pa_dbus_arg_info entry_device_updated_args
[] = { { "device", "s", NULL
} };
279 static pa_dbus_arg_info entry_volume_updated_args
[] = { { "volume", "a(uu)", NULL
} };
280 static pa_dbus_arg_info entry_mute_updated_args
[] = { { "muted", "b", NULL
} };
282 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
283 [SIGNAL_NEW_ENTRY
] = { .name
= "NewEntry", .arguments
= new_entry_args
, .n_arguments
= 1 },
284 [SIGNAL_ENTRY_REMOVED
] = { .name
= "EntryRemoved", .arguments
= entry_removed_args
, .n_arguments
= 1 }
287 static pa_dbus_signal_info entry_signals
[ENTRY_SIGNAL_MAX
] = {
288 [ENTRY_SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= entry_device_updated_args
, .n_arguments
= 1 },
289 [ENTRY_SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= entry_volume_updated_args
, .n_arguments
= 1 },
290 [ENTRY_SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= entry_mute_updated_args
, .n_arguments
= 1 }
293 static pa_dbus_interface_info stream_restore_interface_info
= {
294 .name
= INTERFACE_STREAM_RESTORE
,
295 .method_handlers
= method_handlers
,
296 .n_method_handlers
= METHOD_HANDLER_MAX
,
297 .property_handlers
= property_handlers
,
298 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
299 .get_all_properties_cb
= handle_get_all
,
301 .n_signals
= SIGNAL_MAX
304 static pa_dbus_interface_info entry_interface_info
= {
305 .name
= INTERFACE_ENTRY
,
306 .method_handlers
= entry_method_handlers
,
307 .n_method_handlers
= ENTRY_METHOD_HANDLER_MAX
,
308 .property_handlers
= entry_property_handlers
,
309 .n_property_handlers
= ENTRY_PROPERTY_HANDLER_MAX
,
310 .get_all_properties_cb
= handle_entry_get_all
,
311 .signals
= entry_signals
,
312 .n_signals
= ENTRY_SIGNAL_MAX
315 static struct dbus_entry
*dbus_entry_new(struct userdata
*u
, const char *entry_name
) {
316 struct dbus_entry
*de
;
319 pa_assert(entry_name
);
320 pa_assert(*entry_name
);
322 de
= pa_xnew(struct dbus_entry
, 1);
324 de
->entry_name
= pa_xstrdup(entry_name
);
325 de
->index
= u
->next_index
++;
326 de
->object_path
= pa_sprintf_malloc("%s/%s%u", OBJECT_PATH
, ENTRY_OBJECT_NAME
, de
->index
);
328 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, de
->object_path
, &entry_interface_info
, de
) >= 0);
333 static void dbus_entry_free(struct dbus_entry
*de
) {
336 pa_assert_se(pa_dbus_protocol_remove_interface(de
->userdata
->dbus_protocol
, de
->object_path
, entry_interface_info
.name
) >= 0);
338 pa_xfree(de
->entry_name
);
339 pa_xfree(de
->object_path
);
343 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
344 * are a channel position and a volume value, respectively. The result is
345 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
346 * element. If the data is invalid, an error reply is sent and a negative
347 * number is returned. In case of a failure we make no guarantees about the
348 * state of map and vol. In case of an empty array the channels field of both
349 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
350 * before returning. */
351 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
352 DBusMessageIter array_iter
;
353 DBusMessageIter struct_iter
;
358 pa_assert(pa_streq(dbus_message_iter_get_signature(iter
), "a(uu)"));
362 pa_channel_map_init(map
);
363 pa_cvolume_init(vol
);
368 dbus_message_iter_recurse(iter
, &array_iter
);
370 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
371 dbus_uint32_t chan_pos
;
372 dbus_uint32_t chan_vol
;
374 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
376 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
378 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
379 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
383 pa_assert_se(dbus_message_iter_next(&struct_iter
));
384 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
386 if (!PA_VOLUME_IS_VALID(chan_vol
)) {
387 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
391 if (map
->channels
< PA_CHANNELS_MAX
) {
392 map
->map
[map
->channels
] = chan_pos
;
393 vol
->values
[map
->channels
] = chan_vol
;
398 dbus_message_iter_next(&array_iter
);
401 if (map
->channels
> PA_CHANNELS_MAX
) {
402 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
406 dbus_message_iter_next(iter
);
411 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
412 DBusMessageIter array_iter
;
413 DBusMessageIter struct_iter
;
419 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
421 if (!e
->volume_valid
) {
422 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
426 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
427 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
429 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
430 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
432 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
435 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
438 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
439 DBusMessageIter variant_iter
;
444 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
446 append_volume(&variant_iter
, e
);
448 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
451 static void send_new_entry_signal(struct dbus_entry
*entry
) {
452 DBusMessage
*signal_msg
;
456 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
457 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
458 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
459 dbus_message_unref(signal_msg
);
462 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
463 DBusMessage
*signal_msg
;
467 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
468 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
469 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
470 dbus_message_unref(signal_msg
);
473 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
474 DBusMessage
*signal_msg
;
480 device
= e
->device_valid
? e
->device
: "";
482 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
483 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
484 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
485 dbus_message_unref(signal_msg
);
488 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
489 DBusMessage
*signal_msg
;
490 DBusMessageIter msg_iter
;
495 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
496 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
497 append_volume(&msg_iter
, e
);
498 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
499 dbus_message_unref(signal_msg
);
502 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
503 DBusMessage
*signal_msg
;
509 pa_assert(e
->muted_valid
);
513 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
514 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
515 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
516 dbus_message_unref(signal_msg
);
519 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
520 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
525 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
528 /* The caller frees the array, but not the strings. */
529 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
530 const char **entries
;
533 struct dbus_entry
*de
;
538 *n
= pa_hashmap_size(u
->dbus_entries
);
543 entries
= pa_xnew(const char *, *n
);
545 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
)
546 entries
[i
++] = de
->object_path
;
551 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
552 struct userdata
*u
= userdata
;
553 const char **entries
;
560 entries
= get_entries(u
, &n
);
562 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
567 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
568 struct userdata
*u
= userdata
;
569 DBusMessage
*reply
= NULL
;
570 DBusMessageIter msg_iter
;
571 DBusMessageIter dict_iter
;
572 dbus_uint32_t interface_revision
;
573 const char **entries
;
580 interface_revision
= DBUS_INTERFACE_REVISION
;
581 entries
= get_entries(u
, &n_entries
);
583 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
585 dbus_message_iter_init_append(reply
, &msg_iter
);
586 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
588 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
589 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
591 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
593 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
595 dbus_message_unref(reply
);
600 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
601 struct userdata
*u
= userdata
;
602 DBusMessageIter msg_iter
;
603 const char *name
= NULL
;
604 const char *device
= NULL
;
607 dbus_bool_t muted
= FALSE
;
608 dbus_bool_t apply_immediately
= FALSE
;
609 struct dbus_entry
*dbus_entry
= NULL
;
610 struct entry
*e
= NULL
;
616 pa_assert_se(dbus_message_iter_init(msg
, &msg_iter
));
617 dbus_message_iter_get_basic(&msg_iter
, &name
);
619 pa_assert_se(dbus_message_iter_next(&msg_iter
));
620 dbus_message_iter_get_basic(&msg_iter
, &device
);
622 pa_assert_se(dbus_message_iter_next(&msg_iter
));
623 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
626 dbus_message_iter_get_basic(&msg_iter
, &muted
);
628 pa_assert_se(dbus_message_iter_next(&msg_iter
));
629 dbus_message_iter_get_basic(&msg_iter
, &apply_immediately
);
632 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
636 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
637 pa_bool_t mute_updated
= FALSE
;
638 pa_bool_t volume_updated
= FALSE
;
639 pa_bool_t device_updated
= FALSE
;
641 pa_assert_se(e
= entry_read(u
, name
));
642 mute_updated
= e
->muted
!= muted
;
644 e
->muted_valid
= TRUE
;
646 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
648 e
->channel_map
= map
;
649 e
->volume_valid
= !!map
.channels
;
651 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
653 e
->device
= pa_xstrdup(device
);
654 e
->device_valid
= !!device
[0];
657 send_mute_updated_signal(dbus_entry
, e
);
659 send_volume_updated_signal(dbus_entry
, e
);
661 send_device_updated_signal(dbus_entry
, e
);
664 dbus_entry
= dbus_entry_new(u
, name
);
665 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) == 0);
668 e
->muted_valid
= TRUE
;
669 e
->volume_valid
= !!map
.channels
;
670 e
->device_valid
= !!device
[0];
673 e
->channel_map
= map
;
674 e
->device
= pa_xstrdup(device
);
676 send_new_entry_signal(dbus_entry
);
679 pa_assert_se(entry_write(u
, name
, e
, TRUE
));
681 if (apply_immediately
)
682 entry_apply(u
, name
, e
);
686 pa_dbus_send_empty_reply(conn
, msg
);
691 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
692 struct userdata
*u
= userdata
;
694 struct dbus_entry
*de
;
700 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
));
702 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
703 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
707 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
710 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
711 struct dbus_entry
*de
= userdata
;
717 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
720 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
721 struct dbus_entry
*de
= userdata
;
727 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
730 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
731 struct dbus_entry
*de
= userdata
;
739 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
741 device
= e
->device_valid
? e
->device
: "";
743 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
748 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
749 struct dbus_entry
*de
= userdata
;
759 dbus_message_iter_get_basic(iter
, &device
);
761 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
763 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
767 e
->device
= pa_xstrdup(device
);
768 e
->device_valid
= !!device
[0];
770 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
772 entry_apply(de
->userdata
, de
->entry_name
, e
);
773 send_device_updated_signal(de
, e
);
774 trigger_save(de
->userdata
);
777 pa_dbus_send_empty_reply(conn
, msg
);
782 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
783 struct dbus_entry
*de
= userdata
;
785 DBusMessageIter msg_iter
;
792 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
794 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
796 dbus_message_iter_init_append(reply
, &msg_iter
);
797 append_volume_variant(&msg_iter
, e
);
799 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
804 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
805 struct dbus_entry
*de
= userdata
;
808 struct entry
*e
= NULL
;
809 pa_bool_t updated
= FALSE
;
816 if (get_volume_arg(conn
, msg
, iter
, &map
, &vol
) < 0)
819 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
821 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
825 e
->channel_map
= map
;
826 e
->volume_valid
= !!map
.channels
;
828 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
830 entry_apply(de
->userdata
, de
->entry_name
, e
);
831 send_volume_updated_signal(de
, e
);
832 trigger_save(de
->userdata
);
835 pa_dbus_send_empty_reply(conn
, msg
);
840 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
841 struct dbus_entry
*de
= userdata
;
849 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
851 mute
= e
->muted_valid
? e
->muted
: FALSE
;
853 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &mute
);
858 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
859 struct dbus_entry
*de
= userdata
;
869 dbus_message_iter_get_basic(iter
, &mute
);
871 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
873 updated
= !e
->muted_valid
|| e
->muted
!= mute
;
877 e
->muted_valid
= TRUE
;
879 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
881 entry_apply(de
->userdata
, de
->entry_name
, e
);
882 send_mute_updated_signal(de
, e
);
883 trigger_save(de
->userdata
);
886 pa_dbus_send_empty_reply(conn
, msg
);
891 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
892 struct dbus_entry
*de
= userdata
;
894 DBusMessage
*reply
= NULL
;
895 DBusMessageIter msg_iter
;
896 DBusMessageIter dict_iter
;
897 DBusMessageIter dict_entry_iter
;
905 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
907 device
= e
->device_valid
? e
->device
: "";
908 mute
= e
->muted_valid
? e
->muted
: FALSE
;
910 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
912 dbus_message_iter_init_append(reply
, &msg_iter
);
913 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
915 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
916 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
917 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
919 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
921 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
922 append_volume_variant(&dict_entry_iter
, e
);
924 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
926 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &mute
);
928 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
930 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
932 dbus_message_unref(reply
);
937 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
938 struct dbus_entry
*de
= userdata
;
945 key
.data
= de
->entry_name
;
946 key
.size
= strlen(de
->entry_name
);
948 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
950 send_entry_removed_signal(de
);
951 trigger_save(de
->userdata
);
953 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
956 pa_dbus_send_empty_reply(conn
, msg
);
959 #endif /* HAVE_DBUS */
961 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
962 struct userdata
*u
= userdata
;
968 pa_assert(e
== u
->save_time_event
);
969 u
->core
->mainloop
->time_free(u
->save_time_event
);
970 u
->save_time_event
= NULL
;
972 pa_database_sync(u
->database
);
973 pa_log_info("Synced.");
976 static struct entry
* entry_new(void) {
977 struct entry
*r
= pa_xnew0(struct entry
, 1);
978 r
->version
= ENTRY_VERSION
;
982 static void entry_free(struct entry
* e
) {
990 static pa_bool_t
entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, pa_bool_t replace
) {
999 t
= pa_tagstruct_new(NULL
, 0);
1000 pa_tagstruct_putu8(t
, e
->version
);
1001 pa_tagstruct_put_boolean(t
, e
->volume_valid
);
1002 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
1003 pa_tagstruct_put_cvolume(t
, &e
->volume
);
1004 pa_tagstruct_put_boolean(t
, e
->muted_valid
);
1005 pa_tagstruct_put_boolean(t
, e
->muted
);
1006 pa_tagstruct_put_boolean(t
, e
->device_valid
);
1007 pa_tagstruct_puts(t
, e
->device
);
1008 pa_tagstruct_put_boolean(t
, e
->card_valid
);
1009 pa_tagstruct_puts(t
, e
->card
);
1011 key
.data
= (char *) name
;
1012 key
.size
= strlen(name
);
1014 data
.data
= (void*)pa_tagstruct_data(t
, &data
.size
);
1016 r
= (pa_database_set(u
->database
, &key
, &data
, replace
) == 0);
1018 pa_tagstruct_free(t
);
1023 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1025 #define LEGACY_ENTRY_VERSION 3
1026 static struct entry
*legacy_entry_read(struct userdata
*u
, const char *name
) {
1027 struct legacy_entry
{
1029 pa_bool_t muted_valid
:1, volume_valid
:1, device_valid
:1, card_valid
:1;
1031 pa_channel_map channel_map
;
1033 char device
[PA_NAME_MAX
];
1034 char card
[PA_NAME_MAX
];
1039 struct legacy_entry
*le
;
1045 key
.data
= (char *) name
;
1046 key
.size
= strlen(name
);
1050 if (!pa_database_get(u
->database
, &key
, &data
))
1053 if (data
.size
!= sizeof(struct legacy_entry
)) {
1054 pa_log_debug("Size does not match.");
1058 le
= (struct legacy_entry
*) data
.data
;
1060 if (le
->version
!= LEGACY_ENTRY_VERSION
) {
1061 pa_log_debug("Version mismatch.");
1065 if (!memchr(le
->device
, 0, sizeof(le
->device
))) {
1066 pa_log_warn("Device has missing NUL byte.");
1070 if (!memchr(le
->card
, 0, sizeof(le
->card
))) {
1071 pa_log_warn("Card has missing NUL byte.");
1075 if (le
->device_valid
&& !pa_namereg_is_valid_name(le
->device
)) {
1076 pa_log_warn("Invalid device name stored in database for legacy stream");
1080 if (le
->card_valid
&& !pa_namereg_is_valid_name(le
->card
)) {
1081 pa_log_warn("Invalid card name stored in database for legacy stream");
1085 if (le
->volume_valid
&& !pa_channel_map_valid(&le
->channel_map
)) {
1086 pa_log_warn("Invalid channel map stored in database for legacy stream");
1090 if (le
->volume_valid
&& (!pa_cvolume_valid(&le
->volume
) || !pa_cvolume_compatible_with_channel_map(&le
->volume
, &le
->channel_map
))) {
1091 pa_log_warn("Invalid volume stored in database for legacy stream");
1096 e
->muted_valid
= le
->muted_valid
;
1097 e
->muted
= le
->muted
;
1098 e
->volume_valid
= le
->volume_valid
;
1099 e
->channel_map
= le
->channel_map
;
1100 e
->volume
= le
->volume
;
1101 e
->device_valid
= le
->device_valid
;
1102 e
->device
= pa_xstrdup(le
->device
);
1103 e
->card_valid
= le
->card_valid
;
1104 e
->card
= pa_xstrdup(le
->card
);
1108 pa_datum_free(&data
);
1114 static struct entry
*entry_read(struct userdata
*u
, const char *name
) {
1116 struct entry
*e
= NULL
;
1117 pa_tagstruct
*t
= NULL
;
1118 const char *device
, *card
;
1123 key
.data
= (char*) name
;
1124 key
.size
= strlen(name
);
1128 if (!pa_database_get(u
->database
, &key
, &data
))
1131 t
= pa_tagstruct_new(data
.data
, data
.size
);
1134 if (pa_tagstruct_getu8(t
, &e
->version
) < 0 ||
1135 e
->version
> ENTRY_VERSION
||
1136 pa_tagstruct_get_boolean(t
, &e
->volume_valid
) < 0 ||
1137 pa_tagstruct_get_channel_map(t
, &e
->channel_map
) < 0 ||
1138 pa_tagstruct_get_cvolume(t
, &e
->volume
) < 0 ||
1139 pa_tagstruct_get_boolean(t
, &e
->muted_valid
) < 0 ||
1140 pa_tagstruct_get_boolean(t
, &e
->muted
) < 0 ||
1141 pa_tagstruct_get_boolean(t
, &e
->device_valid
) < 0 ||
1142 pa_tagstruct_gets(t
, &device
) < 0 ||
1143 pa_tagstruct_get_boolean(t
, &e
->card_valid
) < 0 ||
1144 pa_tagstruct_gets(t
, &card
) < 0) {
1149 e
->device
= pa_xstrdup(device
);
1150 e
->card
= pa_xstrdup(card
);
1152 if (!pa_tagstruct_eof(t
))
1155 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1156 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1160 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1161 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1165 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1166 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1170 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1171 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1175 pa_tagstruct_free(t
);
1176 pa_datum_free(&data
);
1184 pa_tagstruct_free(t
);
1186 pa_datum_free(&data
);
1190 static struct entry
* entry_copy(const struct entry
*e
) {
1196 r
->device
= pa_xstrdup(e
->device
);
1197 r
->card
= pa_xstrdup(e
->card
);
1201 static void trigger_save(struct userdata
*u
) {
1202 pa_native_connection
*c
;
1205 PA_IDXSET_FOREACH(c
, u
->subscribed
, idx
) {
1208 t
= pa_tagstruct_new(NULL
, 0);
1209 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1210 pa_tagstruct_putu32(t
, 0);
1211 pa_tagstruct_putu32(t
, u
->module
->index
);
1212 pa_tagstruct_puts(t
, u
->module
->name
);
1213 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1215 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1218 if (u
->save_time_event
)
1221 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1224 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1230 if (a
->device_valid
!= b
->device_valid
||
1231 (a
->device_valid
&& !pa_streq(a
->device
, b
->device
)))
1234 if (a
->card_valid
!= b
->card_valid
||
1235 (a
->card_valid
&& !pa_streq(a
->card
, b
->card
)))
1238 if (a
->muted_valid
!= b
->muted_valid
||
1239 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1243 if (a
->volume_valid
!= b
->volume_valid
||
1244 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1250 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1251 struct userdata
*u
= userdata
;
1252 struct entry
*entry
, *old
= NULL
;
1255 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1256 * clutter these are defined here unconditionally. */
1257 pa_bool_t created_new_entry
= TRUE
;
1258 pa_bool_t device_updated
= FALSE
;
1259 pa_bool_t volume_updated
= FALSE
;
1260 pa_bool_t mute_updated
= FALSE
;
1263 struct dbus_entry
*de
= NULL
;
1269 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1270 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1271 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1272 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1275 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1276 pa_sink_input
*sink_input
;
1278 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1281 if (!(name
= pa_proplist_get_stream_group(sink_input
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1284 if ((old
= entry_read(u
, name
))) {
1285 entry
= entry_copy(old
);
1286 created_new_entry
= FALSE
;
1288 entry
= entry_new();
1290 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1291 pa_assert(sink_input
->volume_writable
);
1293 entry
->channel_map
= sink_input
->channel_map
;
1294 pa_sink_input_get_volume(sink_input
, &entry
->volume
, FALSE
);
1295 entry
->volume_valid
= TRUE
;
1297 volume_updated
= !created_new_entry
1298 && (!old
->volume_valid
1299 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1300 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1303 if (sink_input
->save_muted
) {
1304 entry
->muted
= pa_sink_input_get_mute(sink_input
);
1305 entry
->muted_valid
= TRUE
;
1307 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1310 if (sink_input
->save_sink
) {
1311 pa_xfree(entry
->device
);
1312 entry
->device
= pa_xstrdup(sink_input
->sink
->name
);
1313 entry
->device_valid
= TRUE
;
1315 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1316 if (sink_input
->sink
->card
) {
1317 pa_xfree(entry
->card
);
1318 entry
->card
= pa_xstrdup(sink_input
->sink
->card
->name
);
1319 entry
->card_valid
= TRUE
;
1324 pa_source_output
*source_output
;
1326 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1328 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1331 if (!(name
= pa_proplist_get_stream_group(source_output
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1334 if ((old
= entry_read(u
, name
))) {
1335 entry
= entry_copy(old
);
1336 created_new_entry
= FALSE
;
1338 entry
= entry_new();
1340 if (source_output
->save_volume
&& pa_source_output_is_volume_readable(source_output
)) {
1341 pa_assert(source_output
->volume_writable
);
1343 entry
->channel_map
= source_output
->channel_map
;
1344 pa_source_output_get_volume(source_output
, &entry
->volume
, FALSE
);
1345 entry
->volume_valid
= TRUE
;
1347 volume_updated
= !created_new_entry
1348 && (!old
->volume_valid
1349 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1350 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1353 if (source_output
->save_muted
) {
1354 entry
->muted
= pa_source_output_get_mute(source_output
);
1355 entry
->muted_valid
= TRUE
;
1357 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1360 if (source_output
->save_source
) {
1361 pa_xfree(entry
->device
);
1362 entry
->device
= pa_xstrdup(source_output
->source
->name
);
1363 entry
->device_valid
= TRUE
;
1365 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1367 if (source_output
->source
->card
) {
1368 pa_xfree(entry
->card
);
1369 entry
->card
= pa_xstrdup(source_output
->source
->card
->name
);
1370 entry
->card_valid
= TRUE
;
1379 if (entries_equal(old
, entry
)) {
1389 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1391 if (entry_write(u
, name
, entry
, TRUE
))
1395 if (created_new_entry
) {
1396 de
= dbus_entry_new(u
, name
);
1397 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1398 send_new_entry_signal(de
);
1400 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1403 send_device_updated_signal(de
, entry
);
1405 send_volume_updated_signal(de
, entry
);
1407 send_mute_updated_signal(de
, entry
);
1415 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1420 pa_assert(new_data
);
1422 pa_assert(u
->restore_device
);
1424 if (!(name
= pa_proplist_get_stream_group(new_data
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1428 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1429 else if ((e
= entry_read(u
, name
))) {
1432 if (e
->device_valid
)
1433 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1435 if (!s
&& e
->card_valid
) {
1438 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1439 s
= pa_idxset_first(card
->sinks
, NULL
);
1442 /* It might happen that a stream and a sink are set up at the
1443 same time, in which case we want to make sure we don't
1444 interfere with that */
1445 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1446 if (pa_sink_input_new_data_set_sink(new_data
, s
, TRUE
))
1447 pa_log_info("Restoring device for stream %s.", name
);
1457 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1462 pa_assert(new_data
);
1464 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1466 if (!(name
= pa_proplist_get_stream_group(new_data
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1469 if ((e
= entry_read(u
, name
))) {
1471 if (u
->restore_volume
&& e
->volume_valid
) {
1472 if (!new_data
->volume_writable
)
1473 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1474 else if (new_data
->volume_is_set
)
1475 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1479 pa_log_info("Restoring volume for sink input %s.", name
);
1482 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1483 pa_sink_input_new_data_set_volume(new_data
, &v
);
1485 new_data
->volume_is_absolute
= FALSE
;
1486 new_data
->save_volume
= TRUE
;
1490 if (u
->restore_muted
&& e
->muted_valid
) {
1492 if (!new_data
->muted_is_set
) {
1493 pa_log_info("Restoring mute state for sink input %s.", name
);
1494 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1495 new_data
->save_muted
= TRUE
;
1497 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1508 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1513 pa_assert(new_data
);
1515 pa_assert(u
->restore_device
);
1517 if (new_data
->direct_on_input
)
1520 if (!(name
= pa_proplist_get_stream_group(new_data
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1523 if (new_data
->source
)
1524 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1525 else if ((e
= entry_read(u
, name
))) {
1526 pa_source
*s
= NULL
;
1528 if (e
->device_valid
)
1529 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1531 if (!s
&& e
->card_valid
) {
1534 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1535 s
= pa_idxset_first(card
->sources
, NULL
);
1538 /* It might happen that a stream and a sink are set up at the
1539 same time, in which case we want to make sure we don't
1540 interfere with that */
1541 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1542 pa_log_info("Restoring device for stream %s.", name
);
1543 pa_source_output_new_data_set_source(new_data
, s
, TRUE
);
1554 static pa_hook_result_t
source_output_fixate_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1559 pa_assert(new_data
);
1561 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1563 if (!(name
= pa_proplist_get_stream_group(new_data
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1566 if ((e
= entry_read(u
, name
))) {
1568 if (u
->restore_volume
&& e
->volume_valid
) {
1569 if (!new_data
->volume_writable
)
1570 pa_log_debug("Not restoring volume for source output %s, because its volume can't be changed.", name
);
1571 else if (new_data
->volume_is_set
)
1572 pa_log_debug("Not restoring volume for source output %s, because already set.", name
);
1576 pa_log_info("Restoring volume for source output %s.", name
);
1579 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1580 pa_source_output_new_data_set_volume(new_data
, &v
);
1582 new_data
->volume_is_absolute
= FALSE
;
1583 new_data
->save_volume
= TRUE
;
1587 if (u
->restore_muted
&& e
->muted_valid
) {
1589 if (!new_data
->muted_is_set
) {
1590 pa_log_info("Restoring mute state for source output %s.", name
);
1591 pa_source_output_new_data_set_muted(new_data
, e
->muted
);
1592 new_data
->save_muted
= TRUE
;
1594 pa_log_debug("Not restoring mute state for source output %s, because already set.", name
);
1605 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1612 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1614 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1618 if (si
->sink
== sink
)
1624 /* Skip this if it is already in the process of being moved
1629 /* It might happen that a stream and a sink are set up at the
1630 same time, in which case we want to make sure we don't
1631 interfere with that */
1632 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1635 if (!(name
= pa_proplist_get_stream_group(si
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1638 if ((e
= entry_read(u
, name
))) {
1639 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1640 pa_sink_input_move_to(si
, sink
, TRUE
);
1651 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1652 pa_source_output
*so
;
1658 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1660 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1664 if (so
->source
== source
)
1667 if (so
->save_source
)
1670 if (so
->direct_on_input
)
1673 /* Skip this if it is already in the process of being moved anyway */
1677 /* It might happen that a stream and a source are set up at the
1678 same time, in which case we want to make sure we don't
1679 interfere with that */
1680 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1683 if (!(name
= pa_proplist_get_stream_group(so
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1686 if ((e
= entry_read(u
, name
))) {
1687 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1688 pa_source_output_move_to(so
, source
, TRUE
);
1699 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1706 pa_assert(u
->on_rescue
&& u
->restore_device
);
1708 /* There's no point in doing anything if the core is shut down anyway */
1709 if (c
->state
== PA_CORE_SHUTDOWN
)
1712 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1719 if (!(name
= pa_proplist_get_stream_group(si
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1722 if ((e
= entry_read(u
, name
))) {
1724 if (e
->device_valid
) {
1727 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1729 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1730 pa_sink_input_move_to(si
, d
, TRUE
);
1742 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1743 pa_source_output
*so
;
1749 pa_assert(u
->on_rescue
&& u
->restore_device
);
1751 /* There's no point in doing anything if the core is shut down anyway */
1752 if (c
->state
== PA_CORE_SHUTDOWN
)
1755 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1759 if (so
->direct_on_input
)
1765 if (!(name
= pa_proplist_get_stream_group(so
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1768 if ((e
= entry_read(u
, name
))) {
1770 if (e
->device_valid
) {
1773 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1775 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1776 pa_source_output_move_to(so
, d
, TRUE
);
1788 static int fill_db(struct userdata
*u
, const char *filename
) {
1797 f
= fopen(fn
= pa_xstrdup(filename
), "r");
1799 f
= pa_open_config_file(DEFAULT_FALLBACK_FILE
, DEFAULT_FALLBACK_FILE_USER
, NULL
, &fn
);
1803 pa_log("Failed to open %s: %s", filename
, pa_cstrerror(errno
));
1815 if (!fgets(ln
, sizeof(ln
), f
))
1822 if (!*ln
|| ln
[0] == '#' || ln
[0] == ';')
1825 d
= ln
+strcspn(ln
, WHITESPACE
);
1826 v
= d
+strspn(d
, WHITESPACE
);
1829 pa_log("[%s:%u] failed to parse line - too few words", fn
, n
);
1834 if (pa_atod(v
, &db
) >= 0) {
1840 e
.version
= ENTRY_VERSION
;
1841 e
.volume_valid
= TRUE
;
1842 pa_cvolume_set(&e
.volume
, 1, pa_sw_volume_from_dB(db
));
1843 pa_channel_map_init_mono(&e
.channel_map
);
1845 key
.data
= (void *) ln
;
1846 key
.size
= strlen(ln
);
1848 data
.data
= (void *) &e
;
1849 data
.size
= sizeof(e
);
1851 if (pa_database_set(u
->database
, &key
, &data
, FALSE
) == 0)
1852 pa_log_debug("Setting %s to %0.2f dB.", ln
, db
);
1854 pa_log_warn("[%s:%u] Positive dB values are not allowed, not setting entry %s.", fn
, n
, ln
);
1856 pa_log_warn("[%s:%u] Couldn't parse '%s' as a double, not setting entry %s.", fn
, n
, v
, ln
);
1871 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
) {
1873 pa_source_output
*so
;
1880 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1884 if (!(n
= pa_proplist_get_stream_group(si
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1887 if (!pa_streq(name
, n
)) {
1893 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1897 pa_log_info("Restoring volume for sink input %s.", name
);
1898 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1899 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1902 if (u
->restore_muted
&& e
->muted_valid
) {
1903 pa_log_info("Restoring mute state for sink input %s.", name
);
1904 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1907 if (u
->restore_device
) {
1908 if (!e
->device_valid
) {
1909 if (si
->save_sink
) {
1910 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1911 /* If the device is not valid we should make sure the
1912 save flag is cleared as the user may have specifically
1913 removed the sink element from the rule. */
1914 si
->save_sink
= FALSE
;
1915 /* This is cheating a bit. The sink input itself has not changed
1916 but the rules governing it's routing have, so we fire this event
1917 such that other routing modules (e.g. module-device-manager)
1918 will pick up the change and reapply their routing */
1919 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1921 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1922 pa_log_info("Restoring device for stream %s.", name
);
1923 pa_sink_input_move_to(si
, s
, TRUE
);
1928 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1932 if (!(n
= pa_proplist_get_stream_group(so
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1935 if (!pa_streq(name
, n
)) {
1941 if (u
->restore_volume
&& e
->volume_valid
&& so
->volume_writable
) {
1945 pa_log_info("Restoring volume for source output %s.", name
);
1946 pa_cvolume_remap(&v
, &e
->channel_map
, &so
->channel_map
);
1947 pa_source_output_set_volume(so
, &v
, TRUE
, FALSE
);
1950 if (u
->restore_muted
&& e
->muted_valid
) {
1951 pa_log_info("Restoring mute state for source output %s.", name
);
1952 pa_source_output_set_mute(so
, e
->muted
, TRUE
);
1955 if (u
->restore_device
) {
1956 if (!e
->device_valid
) {
1957 if (so
->save_source
) {
1958 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1959 /* If the device is not valid we should make sure the
1960 save flag is cleared as the user may have specifically
1961 removed the source element from the rule. */
1962 so
->save_source
= FALSE
;
1963 /* This is cheating a bit. The source output itself has not changed
1964 but the rules governing it's routing have, so we fire this event
1965 such that other routing modules (e.g. module-device-manager)
1966 will pick up the change and reapply their routing */
1967 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1969 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1970 pa_log_info("Restoring device for stream %s.", name
);
1971 pa_source_output_move_to(so
, s
, TRUE
);
1978 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1982 done
= !pa_database_first(u
->database
, &key
, NULL
);
1989 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1991 name
= pa_xstrndup(key
.data
, key
.size
);
1992 pa_datum_free(&key
);
1994 if ((e
= entry_read(u
, name
))) {
1996 pa_log("name=%s", name
);
1997 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1998 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1999 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
2000 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
2011 #define EXT_VERSION 1
2013 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
2016 pa_tagstruct
*reply
= NULL
;
2025 if (pa_tagstruct_getu32(t
, &command
) < 0)
2028 reply
= pa_tagstruct_new(NULL
, 0);
2029 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
2030 pa_tagstruct_putu32(reply
, tag
);
2033 case SUBCOMMAND_TEST
: {
2034 if (!pa_tagstruct_eof(t
))
2037 pa_tagstruct_putu32(reply
, EXT_VERSION
);
2041 case SUBCOMMAND_READ
: {
2045 if (!pa_tagstruct_eof(t
))
2048 done
= !pa_database_first(u
->database
, &key
, NULL
);
2055 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2057 name
= pa_xstrndup(key
.data
, key
.size
);
2058 pa_datum_free(&key
);
2060 if ((e
= entry_read(u
, name
))) {
2064 pa_tagstruct_puts(reply
, name
);
2065 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
2066 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
2067 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
2068 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
2081 case SUBCOMMAND_WRITE
: {
2083 pa_bool_t apply_immediately
= FALSE
;
2085 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
2086 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
2089 if (mode
!= PA_UPDATE_MERGE
&&
2090 mode
!= PA_UPDATE_REPLACE
&&
2091 mode
!= PA_UPDATE_SET
)
2094 if (mode
== PA_UPDATE_SET
) {
2096 struct dbus_entry
*de
;
2099 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
2100 send_entry_removed_signal(de
);
2101 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
2104 pa_database_clear(u
->database
);
2107 while (!pa_tagstruct_eof(t
)) {
2108 const char *name
, *device
;
2110 struct entry
*entry
;
2115 entry
= entry_new();
2117 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2118 pa_tagstruct_get_channel_map(t
, &entry
->channel_map
) ||
2119 pa_tagstruct_get_cvolume(t
, &entry
->volume
) < 0 ||
2120 pa_tagstruct_gets(t
, &device
) < 0 ||
2121 pa_tagstruct_get_boolean(t
, &muted
) < 0)
2124 if (!name
|| !*name
) {
2129 entry
->volume_valid
= entry
->volume
.channels
> 0;
2131 if (entry
->volume_valid
)
2132 if (!pa_cvolume_compatible_with_channel_map(&entry
->volume
, &entry
->channel_map
)) {
2137 entry
->muted
= muted
;
2138 entry
->muted_valid
= TRUE
;
2140 entry
->device
= pa_xstrdup(device
);
2141 entry
->device_valid
= device
&& !!entry
->device
[0];
2143 if (entry
->device_valid
&& !pa_namereg_is_valid_name(entry
->device
)) {
2149 old
= entry_read(u
, name
);
2152 pa_log_debug("Client %s changes entry %s.",
2153 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
2156 if (entry_write(u
, name
, entry
, mode
== PA_UPDATE_REPLACE
)) {
2158 struct dbus_entry
*de
;
2161 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
2163 if ((old
->device_valid
!= entry
->device_valid
)
2164 || (entry
->device_valid
&& !pa_streq(entry
->device
, old
->device
)))
2165 send_device_updated_signal(de
, entry
);
2167 if ((old
->volume_valid
!= entry
->volume_valid
)
2168 || (entry
->volume_valid
&& (!pa_cvolume_equal(&entry
->volume
, &old
->volume
)
2169 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
))))
2170 send_volume_updated_signal(de
, entry
);
2172 if (!old
->muted_valid
|| (entry
->muted
!= old
->muted
))
2173 send_mute_updated_signal(de
, entry
);
2176 de
= dbus_entry_new(u
, name
);
2177 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2178 send_new_entry_signal(de
);
2182 if (apply_immediately
)
2183 entry_apply(u
, name
, entry
);
2198 case SUBCOMMAND_DELETE
:
2200 while (!pa_tagstruct_eof(t
)) {
2204 struct dbus_entry
*de
;
2207 if (pa_tagstruct_gets(t
, &name
) < 0)
2211 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
2212 send_entry_removed_signal(de
);
2213 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
2217 key
.data
= (char*) name
;
2218 key
.size
= strlen(name
);
2220 pa_database_unset(u
->database
, &key
);
2227 case SUBCOMMAND_SUBSCRIBE
: {
2231 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
2232 !pa_tagstruct_eof(t
))
2236 pa_idxset_put(u
->subscribed
, c
, NULL
);
2238 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2247 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
2253 pa_tagstruct_free(reply
);
2258 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
2263 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2267 static void clean_up_db(struct userdata
*u
) {
2268 struct clean_up_item
{
2269 PA_LLIST_FIELDS(struct clean_up_item
);
2271 struct entry
*entry
;
2274 PA_LLIST_HEAD(struct clean_up_item
, to_be_removed
);
2275 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
2276 PA_LLIST_HEAD(struct clean_up_item
, to_be_converted
);
2278 pa_bool_t done
= FALSE
;
2280 struct clean_up_item
*item
= NULL
;
2281 struct clean_up_item
*next
= NULL
;
2285 /* It would be convenient to remove or replace the entries in the database
2286 * in the same loop that iterates through the database, but modifying the
2287 * database is not supported while iterating through it. That's why we
2288 * collect the entries that need to be removed or replaced to these
2290 PA_LLIST_HEAD_INIT(struct clean_up_item
, to_be_removed
);
2291 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
2292 PA_LLIST_HEAD_INIT(struct clean_up_item
, to_be_converted
);
2295 done
= !pa_database_first(u
->database
, &key
, NULL
);
2298 char *entry_name
= NULL
;
2299 struct entry
*e
= NULL
;
2301 entry_name
= pa_xstrndup(key
.data
, key
.size
);
2303 /* Use entry_read() to check whether this entry is valid. */
2304 if (!(e
= entry_read(u
, entry_name
))) {
2305 item
= pa_xnew0(struct clean_up_item
, 1);
2306 PA_LLIST_INIT(struct clean_up_item
, item
);
2307 item
->entry_name
= entry_name
;
2309 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
2310 /* entry_read() failed, but what about legacy_entry_read()? */
2311 if (!(e
= legacy_entry_read(u
, entry_name
)))
2312 /* Not a legacy entry either, let's remove this. */
2313 PA_LLIST_PREPEND(struct clean_up_item
, to_be_removed
, item
);
2315 /* Yay, it's valid after all! Now let's convert the entry to the current format. */
2317 PA_LLIST_PREPEND(struct clean_up_item
, to_be_converted
, item
);
2320 /* Invalid entry, let's remove this. */
2321 PA_LLIST_PREPEND(struct clean_up_item
, to_be_removed
, item
);
2324 pa_xfree(entry_name
);
2328 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2329 pa_datum_free(&key
);
2333 PA_LLIST_FOREACH_SAFE(item
, next
, to_be_removed
) {
2334 key
.data
= item
->entry_name
;
2335 key
.size
= strlen(item
->entry_name
);
2337 pa_log_debug("Removing an invalid entry: %s", item
->entry_name
);
2339 pa_assert_se(pa_database_unset(u
->database
, &key
) >= 0);
2342 PA_LLIST_REMOVE(struct clean_up_item
, to_be_removed
, item
);
2343 pa_xfree(item
->entry_name
);
2347 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
2348 PA_LLIST_FOREACH_SAFE(item
, next
, to_be_converted
) {
2349 pa_log_debug("Upgrading a legacy entry to the current format: %s", item
->entry_name
);
2351 pa_assert_se(entry_write(u
, item
->entry_name
, item
->entry
, TRUE
) >= 0);
2354 PA_LLIST_REMOVE(struct clean_up_item
, to_be_converted
, item
);
2355 pa_xfree(item
->entry_name
);
2356 entry_free(item
->entry
);
2362 int pa__init(pa_module
*m
) {
2363 pa_modargs
*ma
= NULL
;
2367 pa_source_output
*so
;
2369 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
2377 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2378 pa_log("Failed to parse module arguments");
2382 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2383 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2384 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2385 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2386 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2387 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2391 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2392 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2394 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2397 u
->restore_device
= restore_device
;
2398 u
->restore_volume
= restore_volume
;
2399 u
->restore_muted
= restore_muted
;
2400 u
->on_hotplug
= on_hotplug
;
2401 u
->on_rescue
= on_rescue
;
2402 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2404 u
->protocol
= pa_native_protocol_get(m
->core
);
2405 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2407 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
);
2409 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2411 if (restore_device
) {
2412 /* A little bit earlier than module-intended-roles ... */
2413 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
);
2414 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
);
2417 if (restore_device
&& on_hotplug
) {
2418 /* A little bit earlier than module-intended-roles ... */
2419 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
);
2420 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
);
2423 if (restore_device
&& on_rescue
) {
2424 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2425 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
);
2426 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
);
2429 if (restore_volume
|| restore_muted
) {
2430 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
);
2431 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
);
2434 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2437 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2438 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2443 pa_log_info("Successfully opened database file '%s'.", fname
);
2448 if (fill_db(u
, pa_modargs_get_value(ma
, "fallback_table", NULL
)) < 0)
2452 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2453 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2455 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2456 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2458 /* Create the initial dbus entries. */
2459 done
= !pa_database_first(u
->database
, &key
, NULL
);
2463 struct dbus_entry
*de
;
2465 name
= pa_xstrndup(key
.data
, key
.size
);
2466 de
= dbus_entry_new(u
, name
);
2467 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2470 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2471 pa_datum_free(&key
);
2476 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2477 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2479 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2480 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2482 pa_modargs_free(ma
);
2489 pa_modargs_free(ma
);
2494 void pa__done(pa_module
*m
) {
2499 if (!(u
= m
->userdata
))
2503 if (u
->dbus_protocol
) {
2504 pa_assert(u
->dbus_entries
);
2506 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2507 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2509 pa_hashmap_free(u
->dbus_entries
, (pa_free_cb_t
) dbus_entry_free
);
2511 pa_dbus_protocol_unref(u
->dbus_protocol
);
2515 if (u
->subscription
)
2516 pa_subscription_free(u
->subscription
);
2518 if (u
->sink_input_new_hook_slot
)
2519 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2520 if (u
->sink_input_fixate_hook_slot
)
2521 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2522 if (u
->source_output_new_hook_slot
)
2523 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2524 if (u
->source_output_fixate_hook_slot
)
2525 pa_hook_slot_free(u
->source_output_fixate_hook_slot
);
2527 if (u
->sink_put_hook_slot
)
2528 pa_hook_slot_free(u
->sink_put_hook_slot
);
2529 if (u
->source_put_hook_slot
)
2530 pa_hook_slot_free(u
->source_put_hook_slot
);
2532 if (u
->sink_unlink_hook_slot
)
2533 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2534 if (u
->source_unlink_hook_slot
)
2535 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2537 if (u
->connection_unlink_hook_slot
)
2538 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2540 if (u
->save_time_event
)
2541 u
->core
->mainloop
->time_free(u
->save_time_event
);
2544 pa_database_close(u
->database
);
2547 pa_native_protocol_remove_ext(u
->protocol
, m
);
2548 pa_native_protocol_unref(u
->protocol
);
2552 pa_idxset_free(u
->subscribed
, NULL
);