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 bool restore_device
:1;
111 bool restore_volume
:1;
112 bool restore_muted
: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 bool muted_valid
, volume_valid
, device_valid
, card_valid
;
132 pa_channel_map channel_map
;
143 SUBCOMMAND_SUBSCRIBE
,
147 static struct entry
* entry_new(void);
148 static void entry_free(struct entry
*e
);
149 static struct entry
*entry_read(struct userdata
*u
, const char *name
);
150 static bool entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, bool replace
);
151 static struct entry
* entry_copy(const struct entry
*e
);
152 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
);
153 static void trigger_save(struct userdata
*u
);
157 #define OBJECT_PATH "/org/pulseaudio/stream_restore1"
158 #define ENTRY_OBJECT_NAME "entry"
159 #define INTERFACE_STREAM_RESTORE "org.PulseAudio.Ext.StreamRestore1"
160 #define INTERFACE_ENTRY INTERFACE_STREAM_RESTORE ".RestoreEntry"
162 #define DBUS_INTERFACE_REVISION 0
165 struct userdata
*userdata
;
172 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
173 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
175 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
177 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
178 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
180 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
181 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
182 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
183 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
184 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
185 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
186 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
187 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
189 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
191 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
193 enum property_handler_index
{
194 PROPERTY_HANDLER_INTERFACE_REVISION
,
195 PROPERTY_HANDLER_ENTRIES
,
199 enum entry_property_handler_index
{
200 ENTRY_PROPERTY_HANDLER_INDEX
,
201 ENTRY_PROPERTY_HANDLER_NAME
,
202 ENTRY_PROPERTY_HANDLER_DEVICE
,
203 ENTRY_PROPERTY_HANDLER_VOLUME
,
204 ENTRY_PROPERTY_HANDLER_MUTE
,
205 ENTRY_PROPERTY_HANDLER_MAX
208 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
209 [PROPERTY_HANDLER_INTERFACE_REVISION
] = { .property_name
= "InterfaceRevision", .type
= "u", .get_cb
= handle_get_interface_revision
, .set_cb
= NULL
},
210 [PROPERTY_HANDLER_ENTRIES
] = { .property_name
= "Entries", .type
= "ao", .get_cb
= handle_get_entries
, .set_cb
= NULL
}
213 static pa_dbus_property_handler entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MAX
] = {
214 [ENTRY_PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_entry_get_index
, .set_cb
= NULL
},
215 [ENTRY_PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_entry_get_name
, .set_cb
= NULL
},
216 [ENTRY_PROPERTY_HANDLER_DEVICE
] = { .property_name
= "Device", .type
= "s", .get_cb
= handle_entry_get_device
, .set_cb
= handle_entry_set_device
},
217 [ENTRY_PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "a(uu)", .get_cb
= handle_entry_get_volume
, .set_cb
= handle_entry_set_volume
},
218 [ENTRY_PROPERTY_HANDLER_MUTE
] = { .property_name
= "Mute", .type
= "b", .get_cb
= handle_entry_get_mute
, .set_cb
= handle_entry_set_mute
}
221 enum method_handler_index
{
222 METHOD_HANDLER_ADD_ENTRY
,
223 METHOD_HANDLER_GET_ENTRY_BY_NAME
,
227 enum entry_method_handler_index
{
228 ENTRY_METHOD_HANDLER_REMOVE
,
229 ENTRY_METHOD_HANDLER_MAX
232 static pa_dbus_arg_info add_entry_args
[] = { { "name", "s", "in" },
233 { "device", "s", "in" },
234 { "volume", "a(uu)", "in" },
235 { "mute", "b", "in" },
236 { "apply_immediately", "b", "in" },
237 { "entry", "o", "out" } };
238 static pa_dbus_arg_info get_entry_by_name_args
[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
240 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
241 [METHOD_HANDLER_ADD_ENTRY
] = {
242 .method_name
= "AddEntry",
243 .arguments
= add_entry_args
,
244 .n_arguments
= sizeof(add_entry_args
) / sizeof(pa_dbus_arg_info
),
245 .receive_cb
= handle_add_entry
},
246 [METHOD_HANDLER_GET_ENTRY_BY_NAME
] = {
247 .method_name
= "GetEntryByName",
248 .arguments
= get_entry_by_name_args
,
249 .n_arguments
= sizeof(get_entry_by_name_args
) / sizeof(pa_dbus_arg_info
),
250 .receive_cb
= handle_get_entry_by_name
}
253 static pa_dbus_method_handler entry_method_handlers
[ENTRY_METHOD_HANDLER_MAX
] = {
254 [ENTRY_METHOD_HANDLER_REMOVE
] = {
255 .method_name
= "Remove",
258 .receive_cb
= handle_entry_remove
}
263 SIGNAL_ENTRY_REMOVED
,
267 enum entry_signal_index
{
268 ENTRY_SIGNAL_DEVICE_UPDATED
,
269 ENTRY_SIGNAL_VOLUME_UPDATED
,
270 ENTRY_SIGNAL_MUTE_UPDATED
,
274 static pa_dbus_arg_info new_entry_args
[] = { { "entry", "o", NULL
} };
275 static pa_dbus_arg_info entry_removed_args
[] = { { "entry", "o", NULL
} };
277 static pa_dbus_arg_info entry_device_updated_args
[] = { { "device", "s", NULL
} };
278 static pa_dbus_arg_info entry_volume_updated_args
[] = { { "volume", "a(uu)", NULL
} };
279 static pa_dbus_arg_info entry_mute_updated_args
[] = { { "muted", "b", NULL
} };
281 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
282 [SIGNAL_NEW_ENTRY
] = { .name
= "NewEntry", .arguments
= new_entry_args
, .n_arguments
= 1 },
283 [SIGNAL_ENTRY_REMOVED
] = { .name
= "EntryRemoved", .arguments
= entry_removed_args
, .n_arguments
= 1 }
286 static pa_dbus_signal_info entry_signals
[ENTRY_SIGNAL_MAX
] = {
287 [ENTRY_SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= entry_device_updated_args
, .n_arguments
= 1 },
288 [ENTRY_SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= entry_volume_updated_args
, .n_arguments
= 1 },
289 [ENTRY_SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= entry_mute_updated_args
, .n_arguments
= 1 }
292 static pa_dbus_interface_info stream_restore_interface_info
= {
293 .name
= INTERFACE_STREAM_RESTORE
,
294 .method_handlers
= method_handlers
,
295 .n_method_handlers
= METHOD_HANDLER_MAX
,
296 .property_handlers
= property_handlers
,
297 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
298 .get_all_properties_cb
= handle_get_all
,
300 .n_signals
= SIGNAL_MAX
303 static pa_dbus_interface_info entry_interface_info
= {
304 .name
= INTERFACE_ENTRY
,
305 .method_handlers
= entry_method_handlers
,
306 .n_method_handlers
= ENTRY_METHOD_HANDLER_MAX
,
307 .property_handlers
= entry_property_handlers
,
308 .n_property_handlers
= ENTRY_PROPERTY_HANDLER_MAX
,
309 .get_all_properties_cb
= handle_entry_get_all
,
310 .signals
= entry_signals
,
311 .n_signals
= ENTRY_SIGNAL_MAX
314 static struct dbus_entry
*dbus_entry_new(struct userdata
*u
, const char *entry_name
) {
315 struct dbus_entry
*de
;
318 pa_assert(entry_name
);
319 pa_assert(*entry_name
);
321 de
= pa_xnew(struct dbus_entry
, 1);
323 de
->entry_name
= pa_xstrdup(entry_name
);
324 de
->index
= u
->next_index
++;
325 de
->object_path
= pa_sprintf_malloc("%s/%s%u", OBJECT_PATH
, ENTRY_OBJECT_NAME
, de
->index
);
327 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, de
->object_path
, &entry_interface_info
, de
) >= 0);
332 static void dbus_entry_free(struct dbus_entry
*de
) {
335 pa_assert_se(pa_dbus_protocol_remove_interface(de
->userdata
->dbus_protocol
, de
->object_path
, entry_interface_info
.name
) >= 0);
337 pa_xfree(de
->entry_name
);
338 pa_xfree(de
->object_path
);
342 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
343 * are a channel position and a volume value, respectively. The result is
344 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
345 * element. If the data is invalid, an error reply is sent and a negative
346 * number is returned. In case of a failure we make no guarantees about the
347 * state of map and vol. In case of an empty array the channels field of both
348 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
349 * before returning. */
350 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
351 DBusMessageIter array_iter
;
352 DBusMessageIter struct_iter
;
357 pa_assert(pa_streq(dbus_message_iter_get_signature(iter
), "a(uu)"));
361 pa_channel_map_init(map
);
362 pa_cvolume_init(vol
);
367 dbus_message_iter_recurse(iter
, &array_iter
);
369 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
370 dbus_uint32_t chan_pos
;
371 dbus_uint32_t chan_vol
;
373 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
375 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
377 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
378 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
382 pa_assert_se(dbus_message_iter_next(&struct_iter
));
383 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
385 if (!PA_VOLUME_IS_VALID(chan_vol
)) {
386 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
390 if (map
->channels
< PA_CHANNELS_MAX
) {
391 map
->map
[map
->channels
] = chan_pos
;
392 vol
->values
[map
->channels
] = chan_vol
;
397 dbus_message_iter_next(&array_iter
);
400 if (map
->channels
> PA_CHANNELS_MAX
) {
401 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
405 dbus_message_iter_next(iter
);
410 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
411 DBusMessageIter array_iter
;
412 DBusMessageIter struct_iter
;
418 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
420 if (!e
->volume_valid
) {
421 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
425 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
426 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
428 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
429 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
431 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
434 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
437 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
438 DBusMessageIter variant_iter
;
443 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
445 append_volume(&variant_iter
, e
);
447 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
450 static void send_new_entry_signal(struct dbus_entry
*entry
) {
451 DBusMessage
*signal_msg
;
455 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
456 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
457 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
458 dbus_message_unref(signal_msg
);
461 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
462 DBusMessage
*signal_msg
;
466 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
467 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
468 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
469 dbus_message_unref(signal_msg
);
472 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
473 DBusMessage
*signal_msg
;
479 device
= e
->device_valid
? e
->device
: "";
481 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
482 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
483 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
484 dbus_message_unref(signal_msg
);
487 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
488 DBusMessage
*signal_msg
;
489 DBusMessageIter msg_iter
;
494 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
495 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
496 append_volume(&msg_iter
, e
);
497 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
498 dbus_message_unref(signal_msg
);
501 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
502 DBusMessage
*signal_msg
;
508 pa_assert(e
->muted_valid
);
512 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
513 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
514 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
515 dbus_message_unref(signal_msg
);
518 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
519 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
524 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
527 /* The caller frees the array, but not the strings. */
528 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
529 const char **entries
;
532 struct dbus_entry
*de
;
537 *n
= pa_hashmap_size(u
->dbus_entries
);
542 entries
= pa_xnew(const char *, *n
);
544 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
)
545 entries
[i
++] = de
->object_path
;
550 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
551 struct userdata
*u
= userdata
;
552 const char **entries
;
559 entries
= get_entries(u
, &n
);
561 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
566 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
567 struct userdata
*u
= userdata
;
568 DBusMessage
*reply
= NULL
;
569 DBusMessageIter msg_iter
;
570 DBusMessageIter dict_iter
;
571 dbus_uint32_t interface_revision
;
572 const char **entries
;
579 interface_revision
= DBUS_INTERFACE_REVISION
;
580 entries
= get_entries(u
, &n_entries
);
582 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
584 dbus_message_iter_init_append(reply
, &msg_iter
);
585 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
587 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
588 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
590 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
592 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
594 dbus_message_unref(reply
);
599 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
600 struct userdata
*u
= userdata
;
601 DBusMessageIter msg_iter
;
602 const char *name
= NULL
;
603 const char *device
= NULL
;
606 dbus_bool_t muted
= FALSE
;
607 dbus_bool_t apply_immediately
= FALSE
;
608 struct dbus_entry
*dbus_entry
= NULL
;
609 struct entry
*e
= NULL
;
615 pa_assert_se(dbus_message_iter_init(msg
, &msg_iter
));
616 dbus_message_iter_get_basic(&msg_iter
, &name
);
618 pa_assert_se(dbus_message_iter_next(&msg_iter
));
619 dbus_message_iter_get_basic(&msg_iter
, &device
);
621 pa_assert_se(dbus_message_iter_next(&msg_iter
));
622 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
625 dbus_message_iter_get_basic(&msg_iter
, &muted
);
627 pa_assert_se(dbus_message_iter_next(&msg_iter
));
628 dbus_message_iter_get_basic(&msg_iter
, &apply_immediately
);
631 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
635 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
636 bool mute_updated
= false;
637 bool volume_updated
= false;
638 bool device_updated
= false;
640 pa_assert_se(e
= entry_read(u
, name
));
641 mute_updated
= e
->muted
!= muted
;
643 e
->muted_valid
= true;
645 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
647 e
->channel_map
= map
;
648 e
->volume_valid
= !!map
.channels
;
650 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
652 e
->device
= pa_xstrdup(device
);
653 e
->device_valid
= !!device
[0];
656 send_mute_updated_signal(dbus_entry
, e
);
658 send_volume_updated_signal(dbus_entry
, e
);
660 send_device_updated_signal(dbus_entry
, e
);
663 dbus_entry
= dbus_entry_new(u
, name
);
664 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) == 0);
667 e
->muted_valid
= true;
668 e
->volume_valid
= !!map
.channels
;
669 e
->device_valid
= !!device
[0];
672 e
->channel_map
= map
;
673 e
->device
= pa_xstrdup(device
);
675 send_new_entry_signal(dbus_entry
);
678 pa_assert_se(entry_write(u
, name
, e
, true));
680 if (apply_immediately
)
681 entry_apply(u
, name
, e
);
685 pa_dbus_send_empty_reply(conn
, msg
);
690 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
691 struct userdata
*u
= userdata
;
693 struct dbus_entry
*de
;
699 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
));
701 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
702 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
706 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
709 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
710 struct dbus_entry
*de
= userdata
;
716 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
719 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
720 struct dbus_entry
*de
= userdata
;
726 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
729 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
730 struct dbus_entry
*de
= userdata
;
738 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
740 device
= e
->device_valid
? e
->device
: "";
742 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
747 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
748 struct dbus_entry
*de
= userdata
;
758 dbus_message_iter_get_basic(iter
, &device
);
760 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
762 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
766 e
->device
= pa_xstrdup(device
);
767 e
->device_valid
= !!device
[0];
769 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, true));
771 entry_apply(de
->userdata
, de
->entry_name
, e
);
772 send_device_updated_signal(de
, e
);
773 trigger_save(de
->userdata
);
776 pa_dbus_send_empty_reply(conn
, msg
);
781 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
782 struct dbus_entry
*de
= userdata
;
784 DBusMessageIter msg_iter
;
791 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
793 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
795 dbus_message_iter_init_append(reply
, &msg_iter
);
796 append_volume_variant(&msg_iter
, e
);
798 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
803 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
804 struct dbus_entry
*de
= userdata
;
807 struct entry
*e
= NULL
;
808 bool updated
= false;
815 if (get_volume_arg(conn
, msg
, iter
, &map
, &vol
) < 0)
818 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
820 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
824 e
->channel_map
= map
;
825 e
->volume_valid
= !!map
.channels
;
827 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, true));
829 entry_apply(de
->userdata
, de
->entry_name
, e
);
830 send_volume_updated_signal(de
, e
);
831 trigger_save(de
->userdata
);
834 pa_dbus_send_empty_reply(conn
, msg
);
839 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
840 struct dbus_entry
*de
= userdata
;
848 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
850 mute
= e
->muted_valid
? e
->muted
: FALSE
;
852 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &mute
);
857 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
858 struct dbus_entry
*de
= userdata
;
868 dbus_message_iter_get_basic(iter
, &mute
);
870 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
872 updated
= !e
->muted_valid
|| e
->muted
!= mute
;
876 e
->muted_valid
= true;
878 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, true));
880 entry_apply(de
->userdata
, de
->entry_name
, e
);
881 send_mute_updated_signal(de
, e
);
882 trigger_save(de
->userdata
);
885 pa_dbus_send_empty_reply(conn
, msg
);
890 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
891 struct dbus_entry
*de
= userdata
;
893 DBusMessage
*reply
= NULL
;
894 DBusMessageIter msg_iter
;
895 DBusMessageIter dict_iter
;
896 DBusMessageIter dict_entry_iter
;
904 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
906 device
= e
->device_valid
? e
->device
: "";
907 mute
= e
->muted_valid
? e
->muted
: FALSE
;
909 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
911 dbus_message_iter_init_append(reply
, &msg_iter
);
912 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
914 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
915 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
916 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
918 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
920 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
921 append_volume_variant(&dict_entry_iter
, e
);
923 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
925 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &mute
);
927 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
929 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
931 dbus_message_unref(reply
);
936 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
937 struct dbus_entry
*de
= userdata
;
944 key
.data
= de
->entry_name
;
945 key
.size
= strlen(de
->entry_name
);
947 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
949 send_entry_removed_signal(de
);
950 trigger_save(de
->userdata
);
952 pa_assert_se(pa_hashmap_remove_and_free(de
->userdata
->dbus_entries
, de
->entry_name
) >= 0);
954 pa_dbus_send_empty_reply(conn
, msg
);
957 #endif /* HAVE_DBUS */
959 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
960 struct userdata
*u
= userdata
;
966 pa_assert(e
== u
->save_time_event
);
967 u
->core
->mainloop
->time_free(u
->save_time_event
);
968 u
->save_time_event
= NULL
;
970 pa_database_sync(u
->database
);
971 pa_log_info("Synced.");
974 static struct entry
* entry_new(void) {
975 struct entry
*r
= pa_xnew0(struct entry
, 1);
976 r
->version
= ENTRY_VERSION
;
980 static void entry_free(struct entry
* e
) {
988 static bool entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, bool replace
) {
997 t
= pa_tagstruct_new(NULL
, 0);
998 pa_tagstruct_putu8(t
, e
->version
);
999 pa_tagstruct_put_boolean(t
, e
->volume_valid
);
1000 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
1001 pa_tagstruct_put_cvolume(t
, &e
->volume
);
1002 pa_tagstruct_put_boolean(t
, e
->muted_valid
);
1003 pa_tagstruct_put_boolean(t
, e
->muted
);
1004 pa_tagstruct_put_boolean(t
, e
->device_valid
);
1005 pa_tagstruct_puts(t
, e
->device
);
1006 pa_tagstruct_put_boolean(t
, e
->card_valid
);
1007 pa_tagstruct_puts(t
, e
->card
);
1009 key
.data
= (char *) name
;
1010 key
.size
= strlen(name
);
1012 data
.data
= (void*)pa_tagstruct_data(t
, &data
.size
);
1014 r
= (pa_database_set(u
->database
, &key
, &data
, replace
) == 0);
1016 pa_tagstruct_free(t
);
1021 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1023 #define LEGACY_ENTRY_VERSION 3
1024 static struct entry
*legacy_entry_read(struct userdata
*u
, const char *name
) {
1025 struct legacy_entry
{
1027 bool muted_valid
:1, volume_valid
:1, device_valid
:1, card_valid
:1;
1029 pa_channel_map channel_map
;
1031 char device
[PA_NAME_MAX
];
1032 char card
[PA_NAME_MAX
];
1037 struct legacy_entry
*le
;
1043 key
.data
= (char *) name
;
1044 key
.size
= strlen(name
);
1048 if (!pa_database_get(u
->database
, &key
, &data
))
1051 if (data
.size
!= sizeof(struct legacy_entry
)) {
1052 pa_log_debug("Size does not match.");
1056 le
= (struct legacy_entry
*) data
.data
;
1058 if (le
->version
!= LEGACY_ENTRY_VERSION
) {
1059 pa_log_debug("Version mismatch.");
1063 if (!memchr(le
->device
, 0, sizeof(le
->device
))) {
1064 pa_log_warn("Device has missing NUL byte.");
1068 if (!memchr(le
->card
, 0, sizeof(le
->card
))) {
1069 pa_log_warn("Card has missing NUL byte.");
1073 if (le
->device_valid
&& !pa_namereg_is_valid_name(le
->device
)) {
1074 pa_log_warn("Invalid device name stored in database for legacy stream");
1078 if (le
->card_valid
&& !pa_namereg_is_valid_name(le
->card
)) {
1079 pa_log_warn("Invalid card name stored in database for legacy stream");
1083 if (le
->volume_valid
&& !pa_channel_map_valid(&le
->channel_map
)) {
1084 pa_log_warn("Invalid channel map stored in database for legacy stream");
1088 if (le
->volume_valid
&& (!pa_cvolume_valid(&le
->volume
) || !pa_cvolume_compatible_with_channel_map(&le
->volume
, &le
->channel_map
))) {
1089 pa_log_warn("Invalid volume stored in database for legacy stream");
1094 e
->muted_valid
= le
->muted_valid
;
1095 e
->muted
= le
->muted
;
1096 e
->volume_valid
= le
->volume_valid
;
1097 e
->channel_map
= le
->channel_map
;
1098 e
->volume
= le
->volume
;
1099 e
->device_valid
= le
->device_valid
;
1100 e
->device
= pa_xstrdup(le
->device
);
1101 e
->card_valid
= le
->card_valid
;
1102 e
->card
= pa_xstrdup(le
->card
);
1106 pa_datum_free(&data
);
1112 static struct entry
*entry_read(struct userdata
*u
, const char *name
) {
1114 struct entry
*e
= NULL
;
1115 pa_tagstruct
*t
= NULL
;
1116 const char *device
, *card
;
1121 key
.data
= (char*) name
;
1122 key
.size
= strlen(name
);
1126 if (!pa_database_get(u
->database
, &key
, &data
))
1129 t
= pa_tagstruct_new(data
.data
, data
.size
);
1132 if (pa_tagstruct_getu8(t
, &e
->version
) < 0 ||
1133 e
->version
> ENTRY_VERSION
||
1134 pa_tagstruct_get_boolean(t
, &e
->volume_valid
) < 0 ||
1135 pa_tagstruct_get_channel_map(t
, &e
->channel_map
) < 0 ||
1136 pa_tagstruct_get_cvolume(t
, &e
->volume
) < 0 ||
1137 pa_tagstruct_get_boolean(t
, &e
->muted_valid
) < 0 ||
1138 pa_tagstruct_get_boolean(t
, &e
->muted
) < 0 ||
1139 pa_tagstruct_get_boolean(t
, &e
->device_valid
) < 0 ||
1140 pa_tagstruct_gets(t
, &device
) < 0 ||
1141 pa_tagstruct_get_boolean(t
, &e
->card_valid
) < 0 ||
1142 pa_tagstruct_gets(t
, &card
) < 0) {
1147 e
->device
= pa_xstrdup(device
);
1148 e
->card
= pa_xstrdup(card
);
1150 if (!pa_tagstruct_eof(t
))
1153 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1154 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1158 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1159 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1163 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1164 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1168 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1169 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1173 pa_tagstruct_free(t
);
1174 pa_datum_free(&data
);
1182 pa_tagstruct_free(t
);
1184 pa_datum_free(&data
);
1188 static struct entry
* entry_copy(const struct entry
*e
) {
1194 r
->device
= pa_xstrdup(e
->device
);
1195 r
->card
= pa_xstrdup(e
->card
);
1199 static void trigger_save(struct userdata
*u
) {
1200 pa_native_connection
*c
;
1203 PA_IDXSET_FOREACH(c
, u
->subscribed
, idx
) {
1206 t
= pa_tagstruct_new(NULL
, 0);
1207 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1208 pa_tagstruct_putu32(t
, 0);
1209 pa_tagstruct_putu32(t
, u
->module
->index
);
1210 pa_tagstruct_puts(t
, u
->module
->name
);
1211 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1213 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1216 if (u
->save_time_event
)
1219 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1222 static bool entries_equal(const struct entry
*a
, const struct entry
*b
) {
1228 if (a
->device_valid
!= b
->device_valid
||
1229 (a
->device_valid
&& !pa_streq(a
->device
, b
->device
)))
1232 if (a
->card_valid
!= b
->card_valid
||
1233 (a
->card_valid
&& !pa_streq(a
->card
, b
->card
)))
1236 if (a
->muted_valid
!= b
->muted_valid
||
1237 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1241 if (a
->volume_valid
!= b
->volume_valid
||
1242 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1248 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1249 struct userdata
*u
= userdata
;
1250 struct entry
*entry
, *old
= NULL
;
1253 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1254 * clutter these are defined here unconditionally. */
1255 bool created_new_entry
= true;
1256 bool device_updated
= false;
1257 bool volume_updated
= false;
1258 bool mute_updated
= false;
1261 struct dbus_entry
*de
= NULL
;
1267 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1268 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1269 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1270 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1273 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1274 pa_sink_input
*sink_input
;
1276 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1279 if (!(name
= pa_proplist_get_stream_group(sink_input
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1282 if ((old
= entry_read(u
, name
))) {
1283 entry
= entry_copy(old
);
1284 created_new_entry
= false;
1286 entry
= entry_new();
1288 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1289 pa_assert(sink_input
->volume_writable
);
1291 entry
->channel_map
= sink_input
->channel_map
;
1292 pa_sink_input_get_volume(sink_input
, &entry
->volume
, false);
1293 entry
->volume_valid
= true;
1295 volume_updated
= !created_new_entry
1296 && (!old
->volume_valid
1297 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1298 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1301 if (sink_input
->save_muted
) {
1302 entry
->muted
= pa_sink_input_get_mute(sink_input
);
1303 entry
->muted_valid
= true;
1305 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1308 if (sink_input
->save_sink
) {
1309 pa_xfree(entry
->device
);
1310 entry
->device
= pa_xstrdup(sink_input
->sink
->name
);
1311 entry
->device_valid
= true;
1313 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1314 if (sink_input
->sink
->card
) {
1315 pa_xfree(entry
->card
);
1316 entry
->card
= pa_xstrdup(sink_input
->sink
->card
->name
);
1317 entry
->card_valid
= true;
1322 pa_source_output
*source_output
;
1324 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1326 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1329 if (!(name
= pa_proplist_get_stream_group(source_output
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1332 if ((old
= entry_read(u
, name
))) {
1333 entry
= entry_copy(old
);
1334 created_new_entry
= false;
1336 entry
= entry_new();
1338 if (source_output
->save_volume
&& pa_source_output_is_volume_readable(source_output
)) {
1339 pa_assert(source_output
->volume_writable
);
1341 entry
->channel_map
= source_output
->channel_map
;
1342 pa_source_output_get_volume(source_output
, &entry
->volume
, false);
1343 entry
->volume_valid
= true;
1345 volume_updated
= !created_new_entry
1346 && (!old
->volume_valid
1347 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1348 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1351 if (source_output
->save_muted
) {
1352 entry
->muted
= pa_source_output_get_mute(source_output
);
1353 entry
->muted_valid
= true;
1355 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1358 if (source_output
->save_source
) {
1359 pa_xfree(entry
->device
);
1360 entry
->device
= pa_xstrdup(source_output
->source
->name
);
1361 entry
->device_valid
= true;
1363 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1365 if (source_output
->source
->card
) {
1366 pa_xfree(entry
->card
);
1367 entry
->card
= pa_xstrdup(source_output
->source
->card
->name
);
1368 entry
->card_valid
= true;
1377 if (entries_equal(old
, entry
)) {
1387 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1389 if (entry_write(u
, name
, entry
, true))
1393 if (created_new_entry
) {
1394 de
= dbus_entry_new(u
, name
);
1395 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1396 send_new_entry_signal(de
);
1398 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1401 send_device_updated_signal(de
, entry
);
1403 send_volume_updated_signal(de
, entry
);
1405 send_mute_updated_signal(de
, entry
);
1413 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1418 pa_assert(new_data
);
1420 pa_assert(u
->restore_device
);
1422 if (!(name
= pa_proplist_get_stream_group(new_data
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1426 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1427 else if ((e
= entry_read(u
, name
))) {
1430 if (e
->device_valid
)
1431 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1433 if (!s
&& e
->card_valid
) {
1436 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1437 s
= pa_idxset_first(card
->sinks
, NULL
);
1440 /* It might happen that a stream and a sink are set up at the
1441 same time, in which case we want to make sure we don't
1442 interfere with that */
1443 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1444 if (pa_sink_input_new_data_set_sink(new_data
, s
, true))
1445 pa_log_info("Restoring device for stream %s.", name
);
1455 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1460 pa_assert(new_data
);
1462 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1464 if (!(name
= pa_proplist_get_stream_group(new_data
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1467 if ((e
= entry_read(u
, name
))) {
1469 if (u
->restore_volume
&& e
->volume_valid
) {
1470 if (!new_data
->volume_writable
)
1471 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1472 else if (new_data
->volume_is_set
)
1473 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1477 pa_log_info("Restoring volume for sink input %s.", name
);
1480 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1481 pa_sink_input_new_data_set_volume(new_data
, &v
);
1483 new_data
->volume_is_absolute
= false;
1484 new_data
->save_volume
= true;
1488 if (u
->restore_muted
&& e
->muted_valid
) {
1490 if (!new_data
->muted_is_set
) {
1491 pa_log_info("Restoring mute state for sink input %s.", name
);
1492 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1493 new_data
->save_muted
= true;
1495 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1506 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1511 pa_assert(new_data
);
1513 pa_assert(u
->restore_device
);
1515 if (new_data
->direct_on_input
)
1518 if (!(name
= pa_proplist_get_stream_group(new_data
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1521 if (new_data
->source
)
1522 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1523 else if ((e
= entry_read(u
, name
))) {
1524 pa_source
*s
= NULL
;
1526 if (e
->device_valid
)
1527 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1529 if (!s
&& e
->card_valid
) {
1532 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1533 s
= pa_idxset_first(card
->sources
, NULL
);
1536 /* It might happen that a stream and a sink are set up at the
1537 same time, in which case we want to make sure we don't
1538 interfere with that */
1539 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1540 pa_log_info("Restoring device for stream %s.", name
);
1541 pa_source_output_new_data_set_source(new_data
, s
, true);
1552 static pa_hook_result_t
source_output_fixate_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1557 pa_assert(new_data
);
1559 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1561 if (!(name
= pa_proplist_get_stream_group(new_data
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1564 if ((e
= entry_read(u
, name
))) {
1566 if (u
->restore_volume
&& e
->volume_valid
) {
1567 if (!new_data
->volume_writable
)
1568 pa_log_debug("Not restoring volume for source output %s, because its volume can't be changed.", name
);
1569 else if (new_data
->volume_is_set
)
1570 pa_log_debug("Not restoring volume for source output %s, because already set.", name
);
1574 pa_log_info("Restoring volume for source output %s.", name
);
1577 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1578 pa_source_output_new_data_set_volume(new_data
, &v
);
1580 new_data
->volume_is_absolute
= false;
1581 new_data
->save_volume
= true;
1585 if (u
->restore_muted
&& e
->muted_valid
) {
1587 if (!new_data
->muted_is_set
) {
1588 pa_log_info("Restoring mute state for source output %s.", name
);
1589 pa_source_output_new_data_set_muted(new_data
, e
->muted
);
1590 new_data
->save_muted
= true;
1592 pa_log_debug("Not restoring mute state for source output %s, because already set.", name
);
1603 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1610 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1612 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1616 if (si
->sink
== sink
)
1622 /* Skip this if it is already in the process of being moved
1627 /* It might happen that a stream and a sink are set up at the
1628 same time, in which case we want to make sure we don't
1629 interfere with that */
1630 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1633 if (!(name
= pa_proplist_get_stream_group(si
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1636 if ((e
= entry_read(u
, name
))) {
1637 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1638 pa_sink_input_move_to(si
, sink
, true);
1649 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1650 pa_source_output
*so
;
1656 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1658 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1662 if (so
->source
== source
)
1665 if (so
->save_source
)
1668 if (so
->direct_on_input
)
1671 /* Skip this if it is already in the process of being moved anyway */
1675 /* It might happen that a stream and a source are set up at the
1676 same time, in which case we want to make sure we don't
1677 interfere with that */
1678 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1681 if (!(name
= pa_proplist_get_stream_group(so
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1684 if ((e
= entry_read(u
, name
))) {
1685 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1686 pa_source_output_move_to(so
, source
, true);
1697 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1704 pa_assert(u
->on_rescue
&& u
->restore_device
);
1706 /* There's no point in doing anything if the core is shut down anyway */
1707 if (c
->state
== PA_CORE_SHUTDOWN
)
1710 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1717 if (!(name
= pa_proplist_get_stream_group(si
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1720 if ((e
= entry_read(u
, name
))) {
1722 if (e
->device_valid
) {
1725 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1727 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1728 pa_sink_input_move_to(si
, d
, true);
1740 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1741 pa_source_output
*so
;
1747 pa_assert(u
->on_rescue
&& u
->restore_device
);
1749 /* There's no point in doing anything if the core is shut down anyway */
1750 if (c
->state
== PA_CORE_SHUTDOWN
)
1753 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1757 if (so
->direct_on_input
)
1763 if (!(name
= pa_proplist_get_stream_group(so
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1766 if ((e
= entry_read(u
, name
))) {
1768 if (e
->device_valid
) {
1771 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1773 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1774 pa_source_output_move_to(so
, d
, true);
1786 static int fill_db(struct userdata
*u
, const char *filename
) {
1795 f
= fopen(fn
= pa_xstrdup(filename
), "r");
1797 f
= pa_open_config_file(DEFAULT_FALLBACK_FILE
, DEFAULT_FALLBACK_FILE_USER
, NULL
, &fn
);
1801 pa_log("Failed to open %s: %s", filename
, pa_cstrerror(errno
));
1813 if (!fgets(ln
, sizeof(ln
), f
))
1820 if (!*ln
|| ln
[0] == '#' || ln
[0] == ';')
1823 d
= ln
+strcspn(ln
, WHITESPACE
);
1824 v
= d
+strspn(d
, WHITESPACE
);
1827 pa_log("[%s:%u] failed to parse line - too few words", fn
, n
);
1832 if (pa_atod(v
, &db
) >= 0) {
1838 e
.version
= ENTRY_VERSION
;
1839 e
.volume_valid
= true;
1840 pa_cvolume_set(&e
.volume
, 1, pa_sw_volume_from_dB(db
));
1841 pa_channel_map_init_mono(&e
.channel_map
);
1843 key
.data
= (void *) ln
;
1844 key
.size
= strlen(ln
);
1846 data
.data
= (void *) &e
;
1847 data
.size
= sizeof(e
);
1849 if (pa_database_set(u
->database
, &key
, &data
, false) == 0)
1850 pa_log_debug("Setting %s to %0.2f dB.", ln
, db
);
1852 pa_log_warn("[%s:%u] Positive dB values are not allowed, not setting entry %s.", fn
, n
, ln
);
1854 pa_log_warn("[%s:%u] Couldn't parse '%s' as a double, not setting entry %s.", fn
, n
, v
, ln
);
1869 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
) {
1871 pa_source_output
*so
;
1878 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1882 if (!(n
= pa_proplist_get_stream_group(si
->proplist
, "sink-input", IDENTIFICATION_PROPERTY
)))
1885 if (!pa_streq(name
, n
)) {
1891 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1895 pa_log_info("Restoring volume for sink input %s.", name
);
1896 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1897 pa_sink_input_set_volume(si
, &v
, true, false);
1900 if (u
->restore_muted
&& e
->muted_valid
) {
1901 pa_log_info("Restoring mute state for sink input %s.", name
);
1902 pa_sink_input_set_mute(si
, e
->muted
, true);
1905 if (u
->restore_device
) {
1906 if (!e
->device_valid
) {
1907 if (si
->save_sink
) {
1908 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1909 /* If the device is not valid we should make sure the
1910 save flag is cleared as the user may have specifically
1911 removed the sink element from the rule. */
1912 si
->save_sink
= false;
1913 /* This is cheating a bit. The sink input itself has not changed
1914 but the rules governing its routing have, so we fire this event
1915 such that other routing modules (e.g. module-device-manager)
1916 will pick up the change and reapply their routing */
1917 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1919 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1920 pa_log_info("Restoring device for stream %s.", name
);
1921 pa_sink_input_move_to(si
, s
, true);
1926 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1930 if (!(n
= pa_proplist_get_stream_group(so
->proplist
, "source-output", IDENTIFICATION_PROPERTY
)))
1933 if (!pa_streq(name
, n
)) {
1939 if (u
->restore_volume
&& e
->volume_valid
&& so
->volume_writable
) {
1943 pa_log_info("Restoring volume for source output %s.", name
);
1944 pa_cvolume_remap(&v
, &e
->channel_map
, &so
->channel_map
);
1945 pa_source_output_set_volume(so
, &v
, true, false);
1948 if (u
->restore_muted
&& e
->muted_valid
) {
1949 pa_log_info("Restoring mute state for source output %s.", name
);
1950 pa_source_output_set_mute(so
, e
->muted
, true);
1953 if (u
->restore_device
) {
1954 if (!e
->device_valid
) {
1955 if (so
->save_source
) {
1956 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1957 /* If the device is not valid we should make sure the
1958 save flag is cleared as the user may have specifically
1959 removed the source element from the rule. */
1960 so
->save_source
= false;
1961 /* This is cheating a bit. The source output itself has not changed
1962 but the rules governing its routing have, so we fire this event
1963 such that other routing modules (e.g. module-device-manager)
1964 will pick up the change and reapply their routing */
1965 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1967 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1968 pa_log_info("Restoring device for stream %s.", name
);
1969 pa_source_output_move_to(so
, s
, true);
1976 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1980 done
= !pa_database_first(u
->database
, &key
, NULL
);
1987 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1989 name
= pa_xstrndup(key
.data
, key
.size
);
1990 pa_datum_free(&key
);
1992 if ((e
= entry_read(u
, name
))) {
1994 pa_log("name=%s", name
);
1995 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1996 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1997 pa_log("volume=%s %s",
1998 pa_cvolume_snprint_verbose(t
, sizeof(t
), &e
->volume
, &e
->channel_map
, true),
1999 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 bool 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 pa_hashmap_remove_and_free(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) {
2126 if (!name
|| !*name
) {
2131 entry
->volume_valid
= entry
->volume
.channels
> 0;
2133 if (entry
->volume_valid
)
2134 if (!pa_cvolume_compatible_with_channel_map(&entry
->volume
, &entry
->channel_map
)) {
2139 entry
->muted
= muted
;
2140 entry
->muted_valid
= true;
2142 entry
->device
= pa_xstrdup(device
);
2143 entry
->device_valid
= device
&& !!entry
->device
[0];
2145 if (entry
->device_valid
&& !pa_namereg_is_valid_name(entry
->device
)) {
2151 old
= entry_read(u
, name
);
2154 pa_log_debug("Client %s changes entry %s.",
2155 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
2158 if (entry_write(u
, name
, entry
, mode
== PA_UPDATE_REPLACE
)) {
2160 struct dbus_entry
*de
;
2163 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
2165 if ((old
->device_valid
!= entry
->device_valid
)
2166 || (entry
->device_valid
&& !pa_streq(entry
->device
, old
->device
)))
2167 send_device_updated_signal(de
, entry
);
2169 if ((old
->volume_valid
!= entry
->volume_valid
)
2170 || (entry
->volume_valid
&& (!pa_cvolume_equal(&entry
->volume
, &old
->volume
)
2171 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
))))
2172 send_volume_updated_signal(de
, entry
);
2174 if (!old
->muted_valid
|| (entry
->muted
!= old
->muted
))
2175 send_mute_updated_signal(de
, entry
);
2178 de
= dbus_entry_new(u
, name
);
2179 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2180 send_new_entry_signal(de
);
2184 if (apply_immediately
)
2185 entry_apply(u
, name
, entry
);
2200 case SUBCOMMAND_DELETE
:
2202 while (!pa_tagstruct_eof(t
)) {
2206 struct dbus_entry
*de
;
2209 if (pa_tagstruct_gets(t
, &name
) < 0)
2213 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
2214 send_entry_removed_signal(de
);
2215 pa_hashmap_remove_and_free(u
->dbus_entries
, name
);
2219 key
.data
= (char*) name
;
2220 key
.size
= strlen(name
);
2222 pa_database_unset(u
->database
, &key
);
2229 case SUBCOMMAND_SUBSCRIBE
: {
2233 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
2234 !pa_tagstruct_eof(t
))
2238 pa_idxset_put(u
->subscribed
, c
, NULL
);
2240 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2249 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
2255 pa_tagstruct_free(reply
);
2260 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
2265 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2269 static void clean_up_db(struct userdata
*u
) {
2270 struct clean_up_item
{
2271 PA_LLIST_FIELDS(struct clean_up_item
);
2273 struct entry
*entry
;
2276 PA_LLIST_HEAD(struct clean_up_item
, to_be_removed
);
2277 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
2278 PA_LLIST_HEAD(struct clean_up_item
, to_be_converted
);
2282 struct clean_up_item
*item
= NULL
;
2283 struct clean_up_item
*next
= NULL
;
2287 /* It would be convenient to remove or replace the entries in the database
2288 * in the same loop that iterates through the database, but modifying the
2289 * database is not supported while iterating through it. That's why we
2290 * collect the entries that need to be removed or replaced to these
2292 PA_LLIST_HEAD_INIT(struct clean_up_item
, to_be_removed
);
2293 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
2294 PA_LLIST_HEAD_INIT(struct clean_up_item
, to_be_converted
);
2297 done
= !pa_database_first(u
->database
, &key
, NULL
);
2300 char *entry_name
= NULL
;
2301 struct entry
*e
= NULL
;
2303 entry_name
= pa_xstrndup(key
.data
, key
.size
);
2305 /* Use entry_read() to check whether this entry is valid. */
2306 if (!(e
= entry_read(u
, entry_name
))) {
2307 item
= pa_xnew0(struct clean_up_item
, 1);
2308 PA_LLIST_INIT(struct clean_up_item
, item
);
2309 item
->entry_name
= entry_name
;
2311 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
2312 /* entry_read() failed, but what about legacy_entry_read()? */
2313 if (!(e
= legacy_entry_read(u
, entry_name
)))
2314 /* Not a legacy entry either, let's remove this. */
2315 PA_LLIST_PREPEND(struct clean_up_item
, to_be_removed
, item
);
2317 /* Yay, it's valid after all! Now let's convert the entry to the current format. */
2319 PA_LLIST_PREPEND(struct clean_up_item
, to_be_converted
, item
);
2322 /* Invalid entry, let's remove this. */
2323 PA_LLIST_PREPEND(struct clean_up_item
, to_be_removed
, item
);
2326 pa_xfree(entry_name
);
2330 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2331 pa_datum_free(&key
);
2335 PA_LLIST_FOREACH_SAFE(item
, next
, to_be_removed
) {
2336 key
.data
= item
->entry_name
;
2337 key
.size
= strlen(item
->entry_name
);
2339 pa_log_debug("Removing an invalid entry: %s", item
->entry_name
);
2341 pa_assert_se(pa_database_unset(u
->database
, &key
) >= 0);
2344 PA_LLIST_REMOVE(struct clean_up_item
, to_be_removed
, item
);
2345 pa_xfree(item
->entry_name
);
2349 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
2350 PA_LLIST_FOREACH_SAFE(item
, next
, to_be_converted
) {
2351 pa_log_debug("Upgrading a legacy entry to the current format: %s", item
->entry_name
);
2353 pa_assert_se(entry_write(u
, item
->entry_name
, item
->entry
, true) >= 0);
2356 PA_LLIST_REMOVE(struct clean_up_item
, to_be_converted
, item
);
2357 pa_xfree(item
->entry_name
);
2358 entry_free(item
->entry
);
2364 int pa__init(pa_module
*m
) {
2365 pa_modargs
*ma
= NULL
;
2369 pa_source_output
*so
;
2371 bool restore_device
= true, restore_volume
= true, restore_muted
= true, on_hotplug
= true, on_rescue
= true;
2379 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2380 pa_log("Failed to parse module arguments");
2384 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2385 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2386 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2387 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2388 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2389 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2393 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2394 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2396 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2399 u
->restore_device
= restore_device
;
2400 u
->restore_volume
= restore_volume
;
2401 u
->restore_muted
= restore_muted
;
2402 u
->on_hotplug
= on_hotplug
;
2403 u
->on_rescue
= on_rescue
;
2404 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2406 u
->protocol
= pa_native_protocol_get(m
->core
);
2407 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2409 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
);
2411 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2413 if (restore_device
) {
2414 /* A little bit earlier than module-intended-roles ... */
2415 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
);
2416 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
);
2419 if (restore_device
&& on_hotplug
) {
2420 /* A little bit earlier than module-intended-roles ... */
2421 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
);
2422 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
);
2425 if (restore_device
&& on_rescue
) {
2426 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2427 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
);
2428 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
);
2431 if (restore_volume
|| restore_muted
) {
2432 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
);
2433 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
);
2436 if (!(fname
= pa_state_path("stream-volumes", true)))
2439 if (!(u
->database
= pa_database_open(fname
, true))) {
2440 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2445 pa_log_info("Successfully opened database file '%s'.", fname
);
2450 if (fill_db(u
, pa_modargs_get_value(ma
, "fallback_table", NULL
)) < 0)
2454 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2455 u
->dbus_entries
= pa_hashmap_new_full(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
, NULL
, (pa_free_cb_t
) dbus_entry_free
);
2457 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2458 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2460 /* Create the initial dbus entries. */
2461 done
= !pa_database_first(u
->database
, &key
, NULL
);
2465 struct dbus_entry
*de
;
2467 name
= pa_xstrndup(key
.data
, key
.size
);
2468 de
= dbus_entry_new(u
, name
);
2469 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2472 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2473 pa_datum_free(&key
);
2478 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2479 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2481 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2482 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2484 pa_modargs_free(ma
);
2491 pa_modargs_free(ma
);
2496 void pa__done(pa_module
*m
) {
2501 if (!(u
= m
->userdata
))
2505 if (u
->dbus_protocol
) {
2506 pa_assert(u
->dbus_entries
);
2508 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2509 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2511 pa_hashmap_free(u
->dbus_entries
);
2513 pa_dbus_protocol_unref(u
->dbus_protocol
);
2517 if (u
->subscription
)
2518 pa_subscription_free(u
->subscription
);
2520 if (u
->sink_input_new_hook_slot
)
2521 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2522 if (u
->sink_input_fixate_hook_slot
)
2523 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2524 if (u
->source_output_new_hook_slot
)
2525 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2526 if (u
->source_output_fixate_hook_slot
)
2527 pa_hook_slot_free(u
->source_output_fixate_hook_slot
);
2529 if (u
->sink_put_hook_slot
)
2530 pa_hook_slot_free(u
->sink_put_hook_slot
);
2531 if (u
->source_put_hook_slot
)
2532 pa_hook_slot_free(u
->source_put_hook_slot
);
2534 if (u
->sink_unlink_hook_slot
)
2535 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2536 if (u
->source_unlink_hook_slot
)
2537 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2539 if (u
->connection_unlink_hook_slot
)
2540 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2542 if (u
->save_time_event
)
2543 u
->core
->mainloop
->time_free(u
->save_time_event
);
2546 pa_database_close(u
->database
);
2549 pa_native_protocol_remove_ext(u
->protocol
, m
);
2550 pa_native_protocol_unref(u
->protocol
);
2554 pa_idxset_free(u
->subscribed
, NULL
);