2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
5 Copyright 2009 Tanu Kaskinen
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <sys/types.h>
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/util.h>
39 #include <pulse/rtclock.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/modargs.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/core-subscribe.h>
47 #include <pulsecore/sink-input.h>
48 #include <pulsecore/source-output.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/protocol-native.h>
51 #include <pulsecore/pstream.h>
52 #include <pulsecore/pstream-util.h>
53 #include <pulsecore/database.h>
56 #include <pulsecore/dbus-util.h>
57 #include <pulsecore/protocol-dbus.h>
60 #include "module-stream-restore-symdef.h"
62 PA_MODULE_AUTHOR("Lennart Poettering");
63 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute/device state of streams");
64 PA_MODULE_VERSION(PACKAGE_VERSION
);
65 PA_MODULE_LOAD_ONCE(TRUE
);
67 "restore_device=<Save/restore sinks/sources?> "
68 "restore_volume=<Save/restore volumes?> "
69 "restore_muted=<Save/restore muted states?> "
70 "on_hotplug=<When new device becomes available, recheck streams?> "
71 "on_rescue=<When device becomes unavailable, recheck streams?>");
73 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
74 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
76 static const char* const valid_modargs
[] = {
88 pa_subscription
*subscription
;
90 *sink_input_new_hook_slot
,
91 *sink_input_fixate_hook_slot
,
92 *source_output_new_hook_slot
,
94 *source_put_hook_slot
,
95 *sink_unlink_hook_slot
,
96 *source_unlink_hook_slot
,
97 *connection_unlink_hook_slot
;
98 pa_time_event
*save_time_event
;
99 pa_database
* database
;
101 pa_bool_t restore_device
:1;
102 pa_bool_t restore_volume
:1;
103 pa_bool_t restore_muted
:1;
104 pa_bool_t on_hotplug
:1;
105 pa_bool_t on_rescue
:1;
107 pa_native_protocol
*protocol
;
108 pa_idxset
*subscribed
;
111 pa_dbus_protocol
*dbus_protocol
;
112 pa_hashmap
*dbus_entries
;
113 uint32_t next_index
; /* For generating object paths for entries. */
117 #define ENTRY_VERSION 3
121 pa_bool_t muted_valid
:1, volume_valid
:1, device_valid
:1, card_valid
:1;
123 pa_channel_map channel_map
;
125 char device
[PA_NAME_MAX
];
126 char card
[PA_NAME_MAX
];
134 SUBCOMMAND_SUBSCRIBE
,
138 static struct entry
*read_entry(struct userdata
*u
, const char *name
);
139 static void apply_entry(struct userdata
*u
, const char *name
, struct entry
*e
);
140 static void trigger_save(struct userdata
*u
);
144 #define OBJECT_PATH "/org/pulseaudio/stream_restore1"
145 #define ENTRY_OBJECT_NAME "entry"
146 #define INTERFACE_STREAM_RESTORE "org.PulseAudio.Ext.StreamRestore1"
147 #define INTERFACE_ENTRY INTERFACE_STREAM_RESTORE ".RestoreEntry"
149 #define DBUS_INTERFACE_REVISION 0
152 struct userdata
*userdata
;
159 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
160 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
162 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
164 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
165 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
167 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
168 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
169 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
170 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
171 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
172 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
173 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
174 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
176 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
178 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
180 enum property_handler_index
{
181 PROPERTY_HANDLER_INTERFACE_REVISION
,
182 PROPERTY_HANDLER_ENTRIES
,
186 enum entry_property_handler_index
{
187 ENTRY_PROPERTY_HANDLER_INDEX
,
188 ENTRY_PROPERTY_HANDLER_NAME
,
189 ENTRY_PROPERTY_HANDLER_DEVICE
,
190 ENTRY_PROPERTY_HANDLER_VOLUME
,
191 ENTRY_PROPERTY_HANDLER_MUTE
,
192 ENTRY_PROPERTY_HANDLER_MAX
195 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
196 [PROPERTY_HANDLER_INTERFACE_REVISION
] = { .property_name
= "InterfaceRevision", .type
= "u", .get_cb
= handle_get_interface_revision
, .set_cb
= NULL
},
197 [PROPERTY_HANDLER_ENTRIES
] = { .property_name
= "Entries", .type
= "ao", .get_cb
= handle_get_entries
, .set_cb
= NULL
}
200 static pa_dbus_property_handler entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MAX
] = {
201 [ENTRY_PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_entry_get_index
, .set_cb
= NULL
},
202 [ENTRY_PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_entry_get_name
, .set_cb
= NULL
},
203 [ENTRY_PROPERTY_HANDLER_DEVICE
] = { .property_name
= "Device", .type
= "s", .get_cb
= handle_entry_get_device
, .set_cb
= handle_entry_set_device
},
204 [ENTRY_PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "a(uu)", .get_cb
= handle_entry_get_volume
, .set_cb
= handle_entry_set_volume
},
205 [ENTRY_PROPERTY_HANDLER_MUTE
] = { .property_name
= "Mute", .type
= "b", .get_cb
= handle_entry_get_mute
, .set_cb
= handle_entry_set_mute
}
208 enum method_handler_index
{
209 METHOD_HANDLER_ADD_ENTRY
,
210 METHOD_HANDLER_GET_ENTRY_BY_NAME
,
214 enum entry_method_handler_index
{
215 ENTRY_METHOD_HANDLER_REMOVE
,
216 ENTRY_METHOD_HANDLER_MAX
219 static pa_dbus_arg_info add_entry_args
[] = { { "name", "s", "in" },
220 { "device", "s", "in" },
221 { "volume", "a(uu)", "in" },
222 { "mute", "b", "in" },
223 { "entry", "o", "out" } };
224 static pa_dbus_arg_info get_entry_by_name_args
[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
226 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
227 [METHOD_HANDLER_ADD_ENTRY
] = {
228 .method_name
= "AddEntry",
229 .arguments
= add_entry_args
,
230 .n_arguments
= sizeof(add_entry_args
) / sizeof(pa_dbus_arg_info
),
231 .receive_cb
= handle_add_entry
},
232 [METHOD_HANDLER_GET_ENTRY_BY_NAME
] = {
233 .method_name
= "GetEntryByName",
234 .arguments
= get_entry_by_name_args
,
235 .n_arguments
= sizeof(get_entry_by_name_args
) / sizeof(pa_dbus_arg_info
),
236 .receive_cb
= handle_get_entry_by_name
}
239 static pa_dbus_method_handler entry_method_handlers
[ENTRY_METHOD_HANDLER_MAX
] = {
240 [ENTRY_METHOD_HANDLER_REMOVE
] = {
241 .method_name
= "Remove",
244 .receive_cb
= handle_entry_remove
}
249 SIGNAL_ENTRY_REMOVED
,
253 enum entry_signal_index
{
254 ENTRY_SIGNAL_DEVICE_UPDATED
,
255 ENTRY_SIGNAL_VOLUME_UPDATED
,
256 ENTRY_SIGNAL_MUTE_UPDATED
,
260 static pa_dbus_arg_info new_entry_args
[] = { { "entry", "o", NULL
} };
261 static pa_dbus_arg_info entry_removed_args
[] = { { "entry", "o", NULL
} };
263 static pa_dbus_arg_info entry_device_updated_args
[] = { { "device", "s", NULL
} };
264 static pa_dbus_arg_info entry_volume_updated_args
[] = { { "volume", "a(uu)", NULL
} };
265 static pa_dbus_arg_info entry_mute_updated_args
[] = { { "muted", "b", NULL
} };
267 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
268 [SIGNAL_NEW_ENTRY
] = { .name
= "NewEntry", .arguments
= new_entry_args
, .n_arguments
= 1 },
269 [SIGNAL_ENTRY_REMOVED
] = { .name
= "EntryRemoved", .arguments
= entry_removed_args
, .n_arguments
= 1 }
272 static pa_dbus_signal_info entry_signals
[ENTRY_SIGNAL_MAX
] = {
273 [ENTRY_SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= entry_device_updated_args
, .n_arguments
= 1 },
274 [ENTRY_SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= entry_volume_updated_args
, .n_arguments
= 1 },
275 [ENTRY_SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= entry_mute_updated_args
, .n_arguments
= 1 }
278 static pa_dbus_interface_info stream_restore_interface_info
= {
279 .name
= INTERFACE_STREAM_RESTORE
,
280 .method_handlers
= method_handlers
,
281 .n_method_handlers
= METHOD_HANDLER_MAX
,
282 .property_handlers
= property_handlers
,
283 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
284 .get_all_properties_cb
= handle_get_all
,
286 .n_signals
= SIGNAL_MAX
289 static pa_dbus_interface_info entry_interface_info
= {
290 .name
= INTERFACE_ENTRY
,
291 .method_handlers
= entry_method_handlers
,
292 .n_method_handlers
= ENTRY_METHOD_HANDLER_MAX
,
293 .property_handlers
= entry_property_handlers
,
294 .n_property_handlers
= ENTRY_PROPERTY_HANDLER_MAX
,
295 .get_all_properties_cb
= handle_entry_get_all
,
296 .signals
= entry_signals
,
297 .n_signals
= ENTRY_SIGNAL_MAX
300 static struct dbus_entry
*dbus_entry_new(struct userdata
*u
, const char *entry_name
) {
301 struct dbus_entry
*de
;
304 pa_assert(entry_name
);
305 pa_assert(*entry_name
);
307 de
= pa_xnew(struct dbus_entry
, 1);
309 de
->entry_name
= pa_xstrdup(entry_name
);
310 de
->index
= u
->next_index
++;
311 de
->object_path
= pa_sprintf_malloc("%s/%s%u", OBJECT_PATH
, ENTRY_OBJECT_NAME
, de
->index
);
313 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, de
->object_path
, &entry_interface_info
, de
) >= 0);
318 static void dbus_entry_free(struct dbus_entry
*de
) {
321 pa_assert_se(pa_dbus_protocol_remove_interface(de
->userdata
->dbus_protocol
, de
->object_path
, entry_interface_info
.name
) >= 0);
323 pa_xfree(de
->entry_name
);
324 pa_xfree(de
->object_path
);
327 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
328 * are a channel position and a volume value, respectively. The result is
329 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
330 * element. If the data is invalid, an error reply is sent and a negative
331 * number is returned. In case of a failure we make no guarantees about the
332 * state of map and vol. In case of an empty array the channels field of both
333 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
334 * before returning. */
335 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
336 DBusMessageIter array_iter
;
337 DBusMessageIter struct_iter
;
342 pa_assert(pa_streq(dbus_message_iter_get_signature(iter
), "a(uu)"));
346 pa_channel_map_init(map
);
347 pa_cvolume_init(vol
);
352 dbus_message_iter_recurse(iter
, &array_iter
);
354 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
355 dbus_uint32_t chan_pos
;
356 dbus_uint32_t chan_vol
;
358 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
360 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
362 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
363 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
367 pa_assert_se(dbus_message_iter_next(&struct_iter
));
368 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
370 if (!PA_VOLUME_IS_VALID(chan_vol
)) {
371 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
375 if (map
->channels
< PA_CHANNELS_MAX
) {
376 map
->map
[map
->channels
] = chan_pos
;
377 vol
->values
[map
->channels
] = chan_vol
;
382 dbus_message_iter_next(&array_iter
);
385 if (map
->channels
> PA_CHANNELS_MAX
) {
386 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
390 dbus_message_iter_next(iter
);
395 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
396 DBusMessageIter array_iter
;
397 DBusMessageIter struct_iter
;
403 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
405 if (!e
->volume_valid
) {
406 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
410 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
411 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
413 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
414 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
416 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
419 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
422 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
423 DBusMessageIter variant_iter
;
428 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
430 append_volume(&variant_iter
, e
);
432 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
435 static void send_new_entry_signal(struct dbus_entry
*entry
) {
436 DBusMessage
*signal_msg
;
440 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
441 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
442 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
443 dbus_message_unref(signal_msg
);
446 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
447 DBusMessage
*signal_msg
;
451 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
452 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
453 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
454 dbus_message_unref(signal_msg
);
457 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
458 DBusMessage
*signal_msg
;
464 device
= e
->device_valid
? e
->device
: "";
466 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
467 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
468 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
469 dbus_message_unref(signal_msg
);
472 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
473 DBusMessage
*signal_msg
;
474 DBusMessageIter msg_iter
;
479 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
480 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
481 append_volume(&msg_iter
, e
);
482 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
483 dbus_message_unref(signal_msg
);
486 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
487 DBusMessage
*signal_msg
;
493 pa_assert(e
->muted_valid
);
497 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
498 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
499 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
500 dbus_message_unref(signal_msg
);
503 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
504 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
509 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
512 /* The caller frees the array, but not the strings. */
513 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
514 const char **entries
;
517 struct dbus_entry
*de
;
522 *n
= pa_hashmap_size(u
->dbus_entries
);
527 entries
= pa_xnew(const char *, *n
);
529 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
)
530 entries
[i
++] = de
->object_path
;
535 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
536 struct userdata
*u
= userdata
;
537 const char **entries
;
544 entries
= get_entries(u
, &n
);
546 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
551 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
552 struct userdata
*u
= userdata
;
553 DBusMessage
*reply
= NULL
;
554 DBusMessageIter msg_iter
;
555 DBusMessageIter dict_iter
;
556 dbus_uint32_t interface_revision
;
557 const char **entries
;
564 interface_revision
= DBUS_INTERFACE_REVISION
;
565 entries
= get_entries(u
, &n_entries
);
567 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
569 dbus_message_iter_init_append(reply
, &msg_iter
);
570 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
572 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
573 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
575 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
577 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
579 dbus_message_unref(reply
);
584 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
585 struct userdata
*u
= userdata
;
586 DBusMessageIter msg_iter
;
587 const char *name
= NULL
;
588 const char *device
= NULL
;
591 dbus_bool_t muted
= FALSE
;
592 dbus_bool_t apply_immediately
= FALSE
;
595 struct dbus_entry
*dbus_entry
= NULL
;
596 struct entry
*e
= NULL
;
602 pa_assert_se(dbus_message_iter_init(msg
, &msg_iter
));
603 dbus_message_iter_get_basic(&msg_iter
, &name
);
605 pa_assert_se(dbus_message_iter_next(&msg_iter
));
606 dbus_message_iter_get_basic(&msg_iter
, &device
);
608 pa_assert_se(dbus_message_iter_next(&msg_iter
));
609 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
612 dbus_message_iter_get_basic(&msg_iter
, &muted
);
614 pa_assert_se(dbus_message_iter_next(&msg_iter
));
615 dbus_message_iter_get_basic(&msg_iter
, &apply_immediately
);
618 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
622 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
623 pa_bool_t mute_updated
= FALSE
;
624 pa_bool_t volume_updated
= FALSE
;
625 pa_bool_t device_updated
= FALSE
;
627 pa_assert_se(e
= read_entry(u
, name
));
628 mute_updated
= e
->muted
!= muted
;
630 e
->muted_valid
= TRUE
;
632 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
634 e
->channel_map
= map
;
635 e
->volume_valid
= !!map
.channels
;
637 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
638 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
639 e
->device_valid
= !!device
[0];
642 send_mute_updated_signal(dbus_entry
, e
);
644 send_volume_updated_signal(dbus_entry
, e
);
646 send_device_updated_signal(dbus_entry
, e
);
649 dbus_entry
= dbus_entry_new(u
, name
);
650 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) == 0);
652 e
= pa_xnew0(struct entry
, 1);
653 e
->version
= ENTRY_VERSION
;
654 e
->muted_valid
= TRUE
;
655 e
->volume_valid
= !!map
.channels
;
656 e
->device_valid
= !!device
[0];
659 e
->channel_map
= map
;
660 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
662 send_new_entry_signal(dbus_entry
);
665 key
.data
= (char *) name
;
666 key
.size
= strlen(name
);
669 value
.size
= sizeof(struct entry
);
671 pa_assert_se(pa_database_set(u
->database
, &key
, &value
, TRUE
) == 0);
672 if (apply_immediately
)
673 apply_entry(u
, name
, e
);
677 pa_dbus_send_empty_reply(conn
, msg
);
682 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
683 struct userdata
*u
= userdata
;
685 struct dbus_entry
*de
;
691 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
));
693 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
694 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
698 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
701 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
702 struct dbus_entry
*de
= userdata
;
708 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
711 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
712 struct dbus_entry
*de
= userdata
;
718 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
721 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
722 struct dbus_entry
*de
= userdata
;
730 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
732 device
= e
->device_valid
? e
->device
: "";
734 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
739 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
740 struct dbus_entry
*de
= userdata
;
750 dbus_message_iter_get_basic(iter
, &device
);
752 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
754 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
760 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
761 e
->device_valid
= !!device
[0];
763 key
.data
= de
->entry_name
;
764 key
.size
= strlen(de
->entry_name
);
766 value
.size
= sizeof(struct entry
);
767 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
769 apply_entry(de
->userdata
, de
->entry_name
, e
);
770 send_device_updated_signal(de
, e
);
771 trigger_save(de
->userdata
);
774 pa_dbus_send_empty_reply(conn
, msg
);
779 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
780 struct dbus_entry
*de
= userdata
;
782 DBusMessageIter msg_iter
;
789 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
791 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
793 dbus_message_iter_init_append(reply
, &msg_iter
);
794 append_volume_variant(&msg_iter
, e
);
796 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
801 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
802 struct dbus_entry
*de
= userdata
;
805 struct entry
*e
= NULL
;
806 pa_bool_t updated
= FALSE
;
813 if (get_volume_arg(conn
, msg
, iter
, &map
, &vol
) < 0)
816 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
818 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
825 e
->channel_map
= map
;
826 e
->volume_valid
= !!map
.channels
;
828 key
.data
= de
->entry_name
;
829 key
.size
= strlen(de
->entry_name
);
831 value
.size
= sizeof(struct entry
);
832 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
834 apply_entry(de
->userdata
, de
->entry_name
, e
);
835 send_volume_updated_signal(de
, e
);
836 trigger_save(de
->userdata
);
839 pa_dbus_send_empty_reply(conn
, msg
);
844 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
845 struct dbus_entry
*de
= userdata
;
853 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
855 mute
= e
->muted_valid
? e
->muted
: FALSE
;
857 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &mute
);
862 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
863 struct dbus_entry
*de
= userdata
;
873 dbus_message_iter_get_basic(iter
, &mute
);
875 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
877 updated
= !e
->muted_valid
|| e
->muted
!= mute
;
884 e
->muted_valid
= TRUE
;
886 key
.data
= de
->entry_name
;
887 key
.size
= strlen(de
->entry_name
);
889 value
.size
= sizeof(struct entry
);
890 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
892 apply_entry(de
->userdata
, de
->entry_name
, e
);
893 send_mute_updated_signal(de
, e
);
894 trigger_save(de
->userdata
);
897 pa_dbus_send_empty_reply(conn
, msg
);
902 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
903 struct dbus_entry
*de
= userdata
;
905 DBusMessage
*reply
= NULL
;
906 DBusMessageIter msg_iter
;
907 DBusMessageIter dict_iter
;
908 DBusMessageIter dict_entry_iter
;
916 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
918 device
= e
->device_valid
? e
->device
: "";
919 mute
= e
->muted_valid
? e
->muted
: FALSE
;
921 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
923 dbus_message_iter_init_append(reply
, &msg_iter
);
924 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
926 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
927 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
928 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
930 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
932 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
933 append_volume_variant(&dict_entry_iter
, e
);
935 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
937 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &mute
);
939 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
941 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
943 dbus_message_unref(reply
);
948 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
949 struct dbus_entry
*de
= userdata
;
956 key
.data
= de
->entry_name
;
957 key
.size
= strlen(de
->entry_name
);
959 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
961 send_entry_removed_signal(de
);
962 trigger_save(de
->userdata
);
964 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
967 pa_dbus_send_empty_reply(conn
, msg
);
970 #endif /* HAVE_DBUS */
972 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
973 struct userdata
*u
= userdata
;
979 pa_assert(e
== u
->save_time_event
);
980 u
->core
->mainloop
->time_free(u
->save_time_event
);
981 u
->save_time_event
= NULL
;
983 pa_database_sync(u
->database
);
984 pa_log_info("Synced.");
987 static char *get_name(pa_proplist
*p
, const char *prefix
) {
994 if ((r
= pa_proplist_gets(p
, IDENTIFICATION_PROPERTY
)))
995 return pa_xstrdup(r
);
997 if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_ROLE
)))
998 t
= pa_sprintf_malloc("%s-by-media-role:%s", prefix
, r
);
999 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_ID
)))
1000 t
= pa_sprintf_malloc("%s-by-application-id:%s", prefix
, r
);
1001 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_NAME
)))
1002 t
= pa_sprintf_malloc("%s-by-application-name:%s", prefix
, r
);
1003 else if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
)))
1004 t
= pa_sprintf_malloc("%s-by-media-name:%s", prefix
, r
);
1006 t
= pa_sprintf_malloc("%s-fallback:%s", prefix
, r
);
1008 pa_proplist_sets(p
, IDENTIFICATION_PROPERTY
, t
);
1012 static struct entry
*read_entry(struct userdata
*u
, const char *name
) {
1019 key
.data
= (char*) name
;
1020 key
.size
= strlen(name
);
1024 if (!pa_database_get(u
->database
, &key
, &data
))
1027 if (data
.size
!= sizeof(struct entry
)) {
1028 /* This is probably just a database upgrade, hence let's not
1029 * consider this more than a debug message */
1030 pa_log_debug("Database contains entry for stream %s of wrong size %lu != %lu. Probably due to uprade, ignoring.", name
, (unsigned long) data
.size
, (unsigned long) sizeof(struct entry
));
1034 e
= (struct entry
*) data
.data
;
1036 if (e
->version
!= ENTRY_VERSION
) {
1037 pa_log_debug("Version of database entry for stream %s doesn't match our version. Probably due to upgrade, ignoring.", name
);
1041 if (!memchr(e
->device
, 0, sizeof(e
->device
))) {
1042 pa_log_warn("Database contains entry for stream %s with missing NUL byte in device name", name
);
1046 if (!memchr(e
->card
, 0, sizeof(e
->card
))) {
1047 pa_log_warn("Database contains entry for stream %s with missing NUL byte in card name", name
);
1051 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1052 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1056 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1057 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1061 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1062 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1066 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1067 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1075 pa_datum_free(&data
);
1079 static void trigger_save(struct userdata
*u
) {
1080 pa_native_connection
*c
;
1083 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1086 t
= pa_tagstruct_new(NULL
, 0);
1087 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1088 pa_tagstruct_putu32(t
, 0);
1089 pa_tagstruct_putu32(t
, u
->module
->index
);
1090 pa_tagstruct_puts(t
, u
->module
->name
);
1091 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1093 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1096 if (u
->save_time_event
)
1099 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1102 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1108 if (a
->device_valid
!= b
->device_valid
||
1109 (a
->device_valid
&& strncmp(a
->device
, b
->device
, sizeof(a
->device
))))
1112 if (a
->card_valid
!= b
->card_valid
||
1113 (a
->card_valid
&& strncmp(a
->card
, b
->card
, sizeof(a
->card
))))
1116 if (a
->muted_valid
!= b
->muted_valid
||
1117 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1121 if (a
->volume_valid
!= b
->volume_valid
||
1122 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1128 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1129 struct userdata
*u
= userdata
;
1130 struct entry entry
, *old
= NULL
;
1134 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1135 * clutter these are defined here unconditionally. */
1136 pa_bool_t created_new_entry
= TRUE
;
1137 pa_bool_t device_updated
= FALSE
;
1138 pa_bool_t volume_updated
= FALSE
;
1139 pa_bool_t mute_updated
= FALSE
;
1142 struct dbus_entry
*de
= NULL
;
1148 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1149 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1150 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1151 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1155 entry
.version
= ENTRY_VERSION
;
1157 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1158 pa_sink_input
*sink_input
;
1160 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1163 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1166 if ((old
= read_entry(u
, name
))) {
1168 created_new_entry
= FALSE
;
1171 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1172 pa_assert(sink_input
->volume_writable
);
1174 entry
.channel_map
= sink_input
->channel_map
;
1175 pa_sink_input_get_volume(sink_input
, &entry
.volume
, FALSE
);
1176 entry
.volume_valid
= TRUE
;
1178 volume_updated
= !created_new_entry
1179 && (!old
->volume_valid
1180 || !pa_channel_map_equal(&entry
.channel_map
, &old
->channel_map
)
1181 || !pa_cvolume_equal(&entry
.volume
, &old
->volume
));
1184 if (sink_input
->save_muted
) {
1185 entry
.muted
= pa_sink_input_get_mute(sink_input
);
1186 entry
.muted_valid
= TRUE
;
1188 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
.muted
!= old
->muted
);
1191 if (sink_input
->save_sink
) {
1192 pa_strlcpy(entry
.device
, sink_input
->sink
->name
, sizeof(entry
.device
));
1193 entry
.device_valid
= TRUE
;
1195 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
.device
, old
->device
));
1196 if (sink_input
->sink
->card
) {
1197 pa_strlcpy(entry
.card
, sink_input
->sink
->card
->name
, sizeof(entry
.card
));
1198 entry
.card_valid
= TRUE
;
1203 pa_source_output
*source_output
;
1205 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1207 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1210 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1213 if ((old
= read_entry(u
, name
))) {
1215 created_new_entry
= FALSE
;
1218 if (source_output
->save_source
) {
1219 pa_strlcpy(entry
.device
, source_output
->source
->name
, sizeof(entry
.device
));
1220 entry
.device_valid
= TRUE
;
1222 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
.device
, old
->device
));
1224 if (source_output
->source
->card
) {
1225 pa_strlcpy(entry
.card
, source_output
->source
->card
->name
, sizeof(entry
.card
));
1226 entry
.card_valid
= TRUE
;
1233 if (entries_equal(old
, &entry
)) {
1243 key
.size
= strlen(name
);
1246 data
.size
= sizeof(entry
);
1248 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1250 pa_database_set(u
->database
, &key
, &data
, TRUE
);
1253 if (created_new_entry
) {
1254 de
= dbus_entry_new(u
, name
);
1255 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1256 send_new_entry_signal(de
);
1258 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1261 send_device_updated_signal(de
, &entry
);
1263 send_volume_updated_signal(de
, &entry
);
1265 send_mute_updated_signal(de
, &entry
);
1274 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1279 pa_assert(new_data
);
1281 pa_assert(u
->restore_device
);
1283 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1287 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1288 else if ((e
= read_entry(u
, name
))) {
1291 if (e
->device_valid
)
1292 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1294 if (!s
&& e
->card_valid
) {
1297 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1298 s
= pa_idxset_first(card
->sinks
, NULL
);
1301 /* It might happen that a stream and a sink are set up at the
1302 same time, in which case we want to make sure we don't
1303 interfere with that */
1304 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1305 if (pa_sink_input_new_data_set_sink(new_data
, s
, TRUE
))
1306 pa_log_info("Restoring device for stream %s.", name
);
1316 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1321 pa_assert(new_data
);
1323 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1325 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1328 if ((e
= read_entry(u
, name
))) {
1330 if (u
->restore_volume
&& e
->volume_valid
) {
1331 if (!new_data
->volume_writable
)
1332 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1333 else if (new_data
->volume_is_set
)
1334 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1338 pa_log_info("Restoring volume for sink input %s.", name
);
1341 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1342 pa_sink_input_new_data_set_volume(new_data
, &v
);
1344 new_data
->volume_is_absolute
= FALSE
;
1345 new_data
->save_volume
= TRUE
;
1349 if (u
->restore_muted
&& e
->muted_valid
) {
1351 if (!new_data
->muted_is_set
) {
1352 pa_log_info("Restoring mute state for sink input %s.", name
);
1353 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1354 new_data
->save_muted
= TRUE
;
1356 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1367 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1372 pa_assert(new_data
);
1374 pa_assert(u
->restore_device
);
1376 if (new_data
->direct_on_input
)
1379 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1382 if (new_data
->source
)
1383 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1384 else if ((e
= read_entry(u
, name
))) {
1385 pa_source
*s
= NULL
;
1387 if (e
->device_valid
)
1388 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1390 if (!s
&& e
->card_valid
) {
1393 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1394 s
= pa_idxset_first(card
->sources
, NULL
);
1397 /* It might happen that a stream and a sink are set up at the
1398 same time, in which case we want to make sure we don't
1399 interfere with that */
1400 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1401 pa_log_info("Restoring device for stream %s.", name
);
1402 pa_source_output_new_data_set_source(new_data
, s
, TRUE
);
1413 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1420 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1422 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1426 if (si
->sink
== sink
)
1432 /* Skip this if it is already in the process of being moved
1437 /* It might happen that a stream and a sink are set up at the
1438 same time, in which case we want to make sure we don't
1439 interfere with that */
1440 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1443 if (!(name
= get_name(si
->proplist
, "sink-input")))
1446 if ((e
= read_entry(u
, name
))) {
1447 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1448 pa_sink_input_move_to(si
, sink
, TRUE
);
1459 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1460 pa_source_output
*so
;
1466 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1468 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1472 if (so
->source
== source
)
1475 if (so
->save_source
)
1478 if (so
->direct_on_input
)
1481 /* Skip this if it is already in the process of being moved anyway */
1485 /* It might happen that a stream and a source are set up at the
1486 same time, in which case we want to make sure we don't
1487 interfere with that */
1488 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1491 if (!(name
= get_name(so
->proplist
, "source-output")))
1494 if ((e
= read_entry(u
, name
))) {
1495 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1496 pa_source_output_move_to(so
, source
, TRUE
);
1507 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1514 pa_assert(u
->on_rescue
&& u
->restore_device
);
1516 /* There's no point in doing anything if the core is shut down anyway */
1517 if (c
->state
== PA_CORE_SHUTDOWN
)
1520 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1527 if (!(name
= get_name(si
->proplist
, "sink-input")))
1530 if ((e
= read_entry(u
, name
))) {
1532 if (e
->device_valid
) {
1535 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1537 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1538 pa_sink_input_move_to(si
, d
, TRUE
);
1550 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1551 pa_source_output
*so
;
1557 pa_assert(u
->on_rescue
&& u
->restore_device
);
1559 /* There's no point in doing anything if the core is shut down anyway */
1560 if (c
->state
== PA_CORE_SHUTDOWN
)
1563 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1567 if (so
->direct_on_input
)
1573 if (!(name
= get_name(so
->proplist
, "source-output")))
1576 if ((e
= read_entry(u
, name
))) {
1578 if (e
->device_valid
) {
1581 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1583 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1584 pa_source_output_move_to(so
, d
, TRUE
);
1596 #define EXT_VERSION 1
1598 static void apply_entry(struct userdata
*u
, const char *name
, struct entry
*e
) {
1600 pa_source_output
*so
;
1607 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1611 if (!(n
= get_name(si
->proplist
, "sink-input")))
1614 if (!pa_streq(name
, n
)) {
1620 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1624 pa_log_info("Restoring volume for sink input %s.", name
);
1625 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1626 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1629 if (u
->restore_muted
&& e
->muted_valid
) {
1630 pa_log_info("Restoring mute state for sink input %s.", name
);
1631 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1634 if (u
->restore_device
) {
1635 if (!e
->device_valid
) {
1636 if (si
->save_sink
) {
1637 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1638 /* If the device is not valid we should make sure the
1639 save flag is cleared as the user may have specifically
1640 removed the sink element from the rule. */
1641 si
->save_sink
= FALSE
;
1642 /* This is cheating a bit. The sink input itself has not changed
1643 but the rules governing it's routing have, so we fire this event
1644 such that other routing modules (e.g. module-device-manager)
1645 will pick up the change and reapply their routing */
1646 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1648 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1649 pa_log_info("Restoring device for stream %s.", name
);
1650 pa_sink_input_move_to(si
, s
, TRUE
);
1655 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1659 if (!(n
= get_name(so
->proplist
, "source-output")))
1662 if (!pa_streq(name
, n
)) {
1668 if (u
->restore_device
) {
1669 if (!e
->device_valid
) {
1670 if (so
->save_source
) {
1671 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1672 /* If the device is not valid we should make sure the
1673 save flag is cleared as the user may have specifically
1674 removed the source element from the rule. */
1675 so
->save_source
= FALSE
;
1676 /* This is cheating a bit. The source output itself has not changed
1677 but the rules governing it's routing have, so we fire this event
1678 such that other routing modules (e.g. module-device-manager)
1679 will pick up the change and reapply their routing */
1680 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1682 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1683 pa_log_info("Restoring device for stream %s.", name
);
1684 pa_source_output_move_to(so
, s
, TRUE
);
1691 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1695 done
= !pa_database_first(u
->database
, &key
, NULL
);
1702 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1704 name
= pa_xstrndup(key
.data
, key
.size
);
1705 pa_datum_free(&key
);
1707 if ((e
= read_entry(u
, name
))) {
1709 pa_log("name=%s", name
);
1710 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1711 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1712 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1713 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1724 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1727 pa_tagstruct
*reply
= NULL
;
1736 if (pa_tagstruct_getu32(t
, &command
) < 0)
1739 reply
= pa_tagstruct_new(NULL
, 0);
1740 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1741 pa_tagstruct_putu32(reply
, tag
);
1744 case SUBCOMMAND_TEST
: {
1745 if (!pa_tagstruct_eof(t
))
1748 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1752 case SUBCOMMAND_READ
: {
1756 if (!pa_tagstruct_eof(t
))
1759 done
= !pa_database_first(u
->database
, &key
, NULL
);
1766 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1768 name
= pa_xstrndup(key
.data
, key
.size
);
1769 pa_datum_free(&key
);
1771 if ((e
= read_entry(u
, name
))) {
1775 pa_tagstruct_puts(reply
, name
);
1776 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1777 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1778 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1779 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1792 case SUBCOMMAND_WRITE
: {
1794 pa_bool_t apply_immediately
= FALSE
;
1796 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1797 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1800 if (mode
!= PA_UPDATE_MERGE
&&
1801 mode
!= PA_UPDATE_REPLACE
&&
1802 mode
!= PA_UPDATE_SET
)
1805 if (mode
== PA_UPDATE_SET
) {
1807 struct dbus_entry
*de
;
1810 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
1811 send_entry_removed_signal(de
);
1812 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
1815 pa_database_clear(u
->database
);
1818 while (!pa_tagstruct_eof(t
)) {
1819 const char *name
, *device
;
1828 entry
.version
= ENTRY_VERSION
;
1830 if (pa_tagstruct_gets(t
, &name
) < 0 ||
1831 pa_tagstruct_get_channel_map(t
, &entry
.channel_map
) ||
1832 pa_tagstruct_get_cvolume(t
, &entry
.volume
) < 0 ||
1833 pa_tagstruct_gets(t
, &device
) < 0 ||
1834 pa_tagstruct_get_boolean(t
, &muted
) < 0)
1837 if (!name
|| !*name
)
1840 entry
.volume_valid
= entry
.volume
.channels
> 0;
1842 if (entry
.volume_valid
)
1843 if (!pa_cvolume_compatible_with_channel_map(&entry
.volume
, &entry
.channel_map
))
1846 entry
.muted
= muted
;
1847 entry
.muted_valid
= TRUE
;
1850 pa_strlcpy(entry
.device
, device
, sizeof(entry
.device
));
1851 entry
.device_valid
= !!entry
.device
[0];
1853 if (entry
.device_valid
&&
1854 !pa_namereg_is_valid_name(entry
.device
))
1858 old
= read_entry(u
, name
);
1861 key
.data
= (char*) name
;
1862 key
.size
= strlen(name
);
1865 data
.size
= sizeof(entry
);
1867 pa_log_debug("Client %s changes entry %s.",
1868 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
1871 if (pa_database_set(u
->database
, &key
, &data
, mode
== PA_UPDATE_REPLACE
) == 0) {
1873 struct dbus_entry
*de
;
1876 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1878 if ((old
->device_valid
!= entry
.device_valid
)
1879 || (entry
.device_valid
&& !pa_streq(entry
.device
, old
->device
)))
1880 send_device_updated_signal(de
, &entry
);
1882 if ((old
->volume_valid
!= entry
.volume_valid
)
1883 || (entry
.volume_valid
&& (!pa_cvolume_equal(&entry
.volume
, &old
->volume
)
1884 || !pa_channel_map_equal(&entry
.channel_map
, &old
->channel_map
))))
1885 send_volume_updated_signal(de
, &entry
);
1887 if (!old
->muted_valid
|| (entry
.muted
!= old
->muted
))
1888 send_mute_updated_signal(de
, &entry
);
1891 de
= dbus_entry_new(u
, name
);
1892 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1893 send_new_entry_signal(de
);
1897 if (apply_immediately
)
1898 apply_entry(u
, name
, &entry
);
1912 case SUBCOMMAND_DELETE
:
1914 while (!pa_tagstruct_eof(t
)) {
1918 struct dbus_entry
*de
;
1921 if (pa_tagstruct_gets(t
, &name
) < 0)
1925 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
1926 send_entry_removed_signal(de
);
1927 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
1931 key
.data
= (char*) name
;
1932 key
.size
= strlen(name
);
1934 pa_database_unset(u
->database
, &key
);
1941 case SUBCOMMAND_SUBSCRIBE
: {
1945 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
1946 !pa_tagstruct_eof(t
))
1950 pa_idxset_put(u
->subscribed
, c
, NULL
);
1952 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
1961 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
1967 pa_tagstruct_free(reply
);
1972 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
1977 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
1981 int pa__init(pa_module
*m
) {
1982 pa_modargs
*ma
= NULL
;
1986 pa_source_output
*so
;
1988 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
1996 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
1997 pa_log("Failed to parse module arguments");
2001 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2002 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2003 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2004 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2005 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2006 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2010 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2011 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2013 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2016 u
->restore_device
= restore_device
;
2017 u
->restore_volume
= restore_volume
;
2018 u
->restore_muted
= restore_muted
;
2019 u
->on_hotplug
= on_hotplug
;
2020 u
->on_rescue
= on_rescue
;
2021 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2023 u
->protocol
= pa_native_protocol_get(m
->core
);
2024 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2026 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
);
2028 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2030 if (restore_device
) {
2031 /* A little bit earlier than module-intended-roles ... */
2032 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
);
2033 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
);
2036 if (restore_device
&& on_hotplug
) {
2037 /* A little bit earlier than module-intended-roles ... */
2038 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
);
2039 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
);
2042 if (restore_device
&& on_rescue
) {
2043 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2044 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
);
2045 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
);
2048 if (restore_volume
|| restore_muted
)
2049 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
);
2051 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2054 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2055 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2060 pa_log_info("Successfully opened database file '%s'.", fname
);
2064 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2065 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2067 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2068 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2070 /* Create the initial dbus entries. */
2071 done
= !pa_database_first(u
->database
, &key
, NULL
);
2075 struct dbus_entry
*de
;
2078 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2080 name
= pa_xstrndup(key
.data
, key
.size
);
2081 pa_datum_free(&key
);
2083 /* Use read_entry() for checking that the entry is valid. */
2084 if ((e
= read_entry(u
, name
))) {
2085 de
= dbus_entry_new(u
, name
);
2086 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2096 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2097 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2099 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2100 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2102 pa_modargs_free(ma
);
2109 pa_modargs_free(ma
);
2115 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2116 struct dbus_entry
*de
= p
;
2120 dbus_entry_free(de
);
2124 void pa__done(pa_module
*m
) {
2129 if (!(u
= m
->userdata
))
2133 if (u
->dbus_protocol
) {
2134 pa_assert(u
->dbus_entries
);
2136 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2137 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2139 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2141 pa_dbus_protocol_unref(u
->dbus_protocol
);
2145 if (u
->subscription
)
2146 pa_subscription_free(u
->subscription
);
2148 if (u
->sink_input_new_hook_slot
)
2149 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2150 if (u
->sink_input_fixate_hook_slot
)
2151 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2152 if (u
->source_output_new_hook_slot
)
2153 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2155 if (u
->sink_put_hook_slot
)
2156 pa_hook_slot_free(u
->sink_put_hook_slot
);
2157 if (u
->source_put_hook_slot
)
2158 pa_hook_slot_free(u
->source_put_hook_slot
);
2160 if (u
->sink_unlink_hook_slot
)
2161 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2162 if (u
->source_unlink_hook_slot
)
2163 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2165 if (u
->connection_unlink_hook_slot
)
2166 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2168 if (u
->save_time_event
)
2169 u
->core
->mainloop
->time_free(u
->save_time_event
);
2172 pa_database_close(u
->database
);
2175 pa_native_protocol_remove_ext(u
->protocol
, m
);
2176 pa_native_protocol_unref(u
->protocol
);
2180 pa_idxset_free(u
->subscribed
, NULL
, NULL
);