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
->muted_valid
= TRUE
;
654 e
->volume_valid
= !!map
.channels
;
655 e
->device_valid
= !!device
[0];
658 e
->channel_map
= map
;
659 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
661 send_new_entry_signal(dbus_entry
);
664 key
.data
= (char *) name
;
665 key
.size
= strlen(name
);
668 value
.size
= sizeof(struct entry
);
670 pa_assert_se(pa_database_set(u
->database
, &key
, &value
, TRUE
) == 0);
671 if (apply_immediately
)
672 apply_entry(u
, name
, e
);
676 pa_dbus_send_empty_reply(conn
, msg
);
681 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
682 struct userdata
*u
= userdata
;
684 struct dbus_entry
*de
;
690 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
));
692 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
693 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
697 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
700 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
701 struct dbus_entry
*de
= userdata
;
707 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
710 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
711 struct dbus_entry
*de
= userdata
;
717 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
720 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
721 struct dbus_entry
*de
= userdata
;
729 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
731 device
= e
->device_valid
? e
->device
: "";
733 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
738 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
739 struct dbus_entry
*de
= userdata
;
749 dbus_message_iter_get_basic(iter
, &device
);
751 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
753 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
759 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
760 e
->device_valid
= !!device
[0];
762 key
.data
= de
->entry_name
;
763 key
.size
= strlen(de
->entry_name
);
765 value
.size
= sizeof(struct entry
);
766 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
768 apply_entry(de
->userdata
, de
->entry_name
, e
);
769 send_device_updated_signal(de
, e
);
770 trigger_save(de
->userdata
);
773 pa_dbus_send_empty_reply(conn
, msg
);
778 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
779 struct dbus_entry
*de
= userdata
;
781 DBusMessageIter msg_iter
;
788 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
790 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
792 dbus_message_iter_init_append(reply
, &msg_iter
);
793 append_volume_variant(&msg_iter
, e
);
795 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
800 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
801 struct dbus_entry
*de
= userdata
;
804 struct entry
*e
= NULL
;
805 pa_bool_t updated
= FALSE
;
812 if (get_volume_arg(conn
, msg
, iter
, &map
, &vol
) < 0)
815 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
817 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
824 e
->channel_map
= map
;
825 e
->volume_valid
= !!map
.channels
;
827 key
.data
= de
->entry_name
;
828 key
.size
= strlen(de
->entry_name
);
830 value
.size
= sizeof(struct entry
);
831 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
833 apply_entry(de
->userdata
, de
->entry_name
, e
);
834 send_volume_updated_signal(de
, e
);
835 trigger_save(de
->userdata
);
838 pa_dbus_send_empty_reply(conn
, msg
);
843 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
844 struct dbus_entry
*de
= userdata
;
852 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
854 mute
= e
->muted_valid
? e
->muted
: FALSE
;
856 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &mute
);
861 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
862 struct dbus_entry
*de
= userdata
;
872 dbus_message_iter_get_basic(iter
, &mute
);
874 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
876 updated
= !e
->muted_valid
|| e
->muted
!= mute
;
883 e
->muted_valid
= TRUE
;
885 key
.data
= de
->entry_name
;
886 key
.size
= strlen(de
->entry_name
);
888 value
.size
= sizeof(struct entry
);
889 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
891 apply_entry(de
->userdata
, de
->entry_name
, e
);
892 send_mute_updated_signal(de
, e
);
893 trigger_save(de
->userdata
);
896 pa_dbus_send_empty_reply(conn
, msg
);
901 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
902 struct dbus_entry
*de
= userdata
;
904 DBusMessage
*reply
= NULL
;
905 DBusMessageIter msg_iter
;
906 DBusMessageIter dict_iter
;
907 DBusMessageIter dict_entry_iter
;
915 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
917 device
= e
->device_valid
? e
->device
: "";
918 mute
= e
->muted_valid
? e
->muted
: FALSE
;
920 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
922 dbus_message_iter_init_append(reply
, &msg_iter
);
923 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
925 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
926 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
927 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
929 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
931 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
932 append_volume_variant(&dict_entry_iter
, e
);
934 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
936 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &mute
);
938 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
940 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
942 dbus_message_unref(reply
);
947 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
948 struct dbus_entry
*de
= userdata
;
955 key
.data
= de
->entry_name
;
956 key
.size
= strlen(de
->entry_name
);
958 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
960 send_entry_removed_signal(de
);
961 trigger_save(de
->userdata
);
963 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
966 pa_dbus_send_empty_reply(conn
, msg
);
969 #endif /* HAVE_DBUS */
971 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
972 struct userdata
*u
= userdata
;
978 pa_assert(e
== u
->save_time_event
);
979 u
->core
->mainloop
->time_free(u
->save_time_event
);
980 u
->save_time_event
= NULL
;
982 pa_database_sync(u
->database
);
983 pa_log_info("Synced.");
986 static char *get_name(pa_proplist
*p
, const char *prefix
) {
993 if ((r
= pa_proplist_gets(p
, IDENTIFICATION_PROPERTY
)))
994 return pa_xstrdup(r
);
996 if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_ROLE
)))
997 t
= pa_sprintf_malloc("%s-by-media-role:%s", prefix
, r
);
998 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_ID
)))
999 t
= pa_sprintf_malloc("%s-by-application-id:%s", prefix
, r
);
1000 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_NAME
)))
1001 t
= pa_sprintf_malloc("%s-by-application-name:%s", prefix
, r
);
1002 else if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
)))
1003 t
= pa_sprintf_malloc("%s-by-media-name:%s", prefix
, r
);
1005 t
= pa_sprintf_malloc("%s-fallback:%s", prefix
, r
);
1007 pa_proplist_sets(p
, IDENTIFICATION_PROPERTY
, t
);
1011 static struct entry
*read_entry(struct userdata
*u
, const char *name
) {
1018 key
.data
= (char*) name
;
1019 key
.size
= strlen(name
);
1023 if (!pa_database_get(u
->database
, &key
, &data
))
1026 if (data
.size
!= sizeof(struct entry
)) {
1027 /* This is probably just a database upgrade, hence let's not
1028 * consider this more than a debug message */
1029 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
));
1033 e
= (struct entry
*) data
.data
;
1035 if (e
->version
!= ENTRY_VERSION
) {
1036 pa_log_debug("Version of database entry for stream %s doesn't match our version. Probably due to upgrade, ignoring.", name
);
1040 if (!memchr(e
->device
, 0, sizeof(e
->device
))) {
1041 pa_log_warn("Database contains entry for stream %s with missing NUL byte in device name", name
);
1045 if (!memchr(e
->card
, 0, sizeof(e
->card
))) {
1046 pa_log_warn("Database contains entry for stream %s with missing NUL byte in card name", name
);
1050 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1051 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1055 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1056 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1060 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1061 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1065 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1066 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1074 pa_datum_free(&data
);
1078 static void trigger_save(struct userdata
*u
) {
1079 pa_native_connection
*c
;
1082 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1085 t
= pa_tagstruct_new(NULL
, 0);
1086 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1087 pa_tagstruct_putu32(t
, 0);
1088 pa_tagstruct_putu32(t
, u
->module
->index
);
1089 pa_tagstruct_puts(t
, u
->module
->name
);
1090 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1092 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1095 if (u
->save_time_event
)
1098 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1101 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1107 if (a
->device_valid
!= b
->device_valid
||
1108 (a
->device_valid
&& strncmp(a
->device
, b
->device
, sizeof(a
->device
))))
1111 if (a
->card_valid
!= b
->card_valid
||
1112 (a
->card_valid
&& strncmp(a
->card
, b
->card
, sizeof(a
->card
))))
1115 if (a
->muted_valid
!= b
->muted_valid
||
1116 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1120 if (a
->volume_valid
!= b
->volume_valid
||
1121 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1127 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1128 struct userdata
*u
= userdata
;
1129 struct entry entry
, *old
= NULL
;
1133 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1134 * clutter these are defined here unconditionally. */
1135 pa_bool_t created_new_entry
= TRUE
;
1136 pa_bool_t device_updated
= FALSE
;
1137 pa_bool_t volume_updated
= FALSE
;
1138 pa_bool_t mute_updated
= FALSE
;
1141 struct dbus_entry
*de
= NULL
;
1147 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1148 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1149 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1150 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1154 entry
.version
= ENTRY_VERSION
;
1156 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1157 pa_sink_input
*sink_input
;
1159 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1162 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1165 if ((old
= read_entry(u
, name
))) {
1167 created_new_entry
= FALSE
;
1170 if (sink_input
->save_volume
) {
1171 pa_assert(pa_sink_input_is_volume_writable(sink_input
));
1173 entry
.channel_map
= sink_input
->channel_map
;
1174 pa_sink_input_get_volume(sink_input
, &entry
.volume
, FALSE
);
1175 entry
.volume_valid
= TRUE
;
1177 volume_updated
= !created_new_entry
1178 && (!old
->volume_valid
1179 || !pa_channel_map_equal(&entry
.channel_map
, &old
->channel_map
)
1180 || !pa_cvolume_equal(&entry
.volume
, &old
->volume
));
1183 if (sink_input
->save_muted
) {
1184 entry
.muted
= pa_sink_input_get_mute(sink_input
);
1185 entry
.muted_valid
= TRUE
;
1187 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
.muted
!= old
->muted
);
1190 if (sink_input
->save_sink
) {
1191 pa_strlcpy(entry
.device
, sink_input
->sink
->name
, sizeof(entry
.device
));
1192 entry
.device_valid
= TRUE
;
1194 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
.device
, old
->device
));
1195 if (sink_input
->sink
->card
) {
1196 pa_strlcpy(entry
.card
, sink_input
->sink
->card
->name
, sizeof(entry
.card
));
1197 entry
.card_valid
= TRUE
;
1202 pa_source_output
*source_output
;
1204 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1206 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1209 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1212 if ((old
= read_entry(u
, name
))) {
1214 created_new_entry
= FALSE
;
1217 if (source_output
->save_source
) {
1218 pa_strlcpy(entry
.device
, source_output
->source
->name
, sizeof(entry
.device
));
1219 entry
.device_valid
= source_output
->save_source
;
1221 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
.device
, old
->device
));
1223 if (source_output
->source
->card
) {
1224 pa_strlcpy(entry
.card
, source_output
->source
->card
->name
, sizeof(entry
.card
));
1225 entry
.card_valid
= TRUE
;
1232 if (entries_equal(old
, &entry
)) {
1242 key
.size
= strlen(name
);
1245 data
.size
= sizeof(entry
);
1247 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1249 pa_database_set(u
->database
, &key
, &data
, TRUE
);
1252 if (created_new_entry
) {
1253 de
= dbus_entry_new(u
, name
);
1254 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1255 send_new_entry_signal(de
);
1257 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1260 send_device_updated_signal(de
, &entry
);
1262 send_volume_updated_signal(de
, &entry
);
1264 send_mute_updated_signal(de
, &entry
);
1273 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1278 pa_assert(new_data
);
1280 pa_assert(u
->restore_device
);
1282 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1286 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1287 else if ((e
= read_entry(u
, name
))) {
1290 if (e
->device_valid
)
1291 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1293 if (!s
&& e
->card_valid
) {
1296 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1297 s
= pa_idxset_first(card
->sinks
, NULL
);
1300 /* It might happen that a stream and a sink are set up at the
1301 same time, in which case we want to make sure we don't
1302 interfere with that */
1303 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
))) {
1304 pa_log_info("Restoring device for stream %s.", name
);
1306 new_data
->save_sink
= TRUE
;
1317 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1322 pa_assert(new_data
);
1324 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1326 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1329 if ((e
= read_entry(u
, name
))) {
1331 if (u
->restore_volume
&& e
->volume_valid
) {
1332 if (!pa_sink_input_new_data_is_volume_writable(new_data
))
1333 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1334 else if (new_data
->volume_is_set
)
1335 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1339 pa_log_info("Restoring volume for sink input %s.", name
);
1342 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1343 pa_sink_input_new_data_set_volume(new_data
, &v
);
1345 new_data
->volume_is_absolute
= FALSE
;
1346 new_data
->save_volume
= TRUE
;
1350 if (u
->restore_muted
&& e
->muted_valid
) {
1352 if (!new_data
->muted_is_set
) {
1353 pa_log_info("Restoring mute state for sink input %s.", name
);
1354 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1355 new_data
->save_muted
= TRUE
;
1357 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1368 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1373 pa_assert(new_data
);
1375 pa_assert(u
->restore_device
);
1377 if (new_data
->direct_on_input
)
1380 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1383 if (new_data
->source
)
1384 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1385 else if ((e
= read_entry(u
, name
))) {
1386 pa_source
*s
= NULL
;
1388 if (e
->device_valid
)
1389 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1391 if (!s
&& e
->card_valid
) {
1394 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1395 s
= pa_idxset_first(card
->sources
, NULL
);
1398 /* It might happen that a stream and a sink are set up at the
1399 same time, in which case we want to make sure we don't
1400 interfere with that */
1401 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1402 pa_log_info("Restoring device for stream %s.", name
);
1403 new_data
->source
= s
;
1404 new_data
->save_source
= TRUE
;
1415 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1422 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1424 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1428 if (si
->sink
== sink
)
1434 /* Skip this if it is already in the process of being moved
1439 /* It might happen that a stream and a sink are set up at the
1440 same time, in which case we want to make sure we don't
1441 interfere with that */
1442 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1445 if (!(name
= get_name(si
->proplist
, "sink-input")))
1448 if ((e
= read_entry(u
, name
))) {
1449 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1450 pa_sink_input_move_to(si
, sink
, TRUE
);
1461 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1462 pa_source_output
*so
;
1468 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1470 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1474 if (so
->source
== source
)
1477 if (so
->save_source
)
1480 if (so
->direct_on_input
)
1483 /* Skip this if it is already in the process of being moved anyway */
1487 /* It might happen that a stream and a source are set up at the
1488 same time, in which case we want to make sure we don't
1489 interfere with that */
1490 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1493 if (!(name
= get_name(so
->proplist
, "source-output")))
1496 if ((e
= read_entry(u
, name
))) {
1497 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1498 pa_source_output_move_to(so
, source
, TRUE
);
1509 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1516 pa_assert(u
->on_rescue
&& u
->restore_device
);
1518 /* There's no point in doing anything if the core is shut down anyway */
1519 if (c
->state
== PA_CORE_SHUTDOWN
)
1522 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1529 if (!(name
= get_name(si
->proplist
, "sink-input")))
1532 if ((e
= read_entry(u
, name
))) {
1534 if (e
->device_valid
) {
1537 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1539 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1540 pa_sink_input_move_to(si
, d
, TRUE
);
1552 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1553 pa_source_output
*so
;
1559 pa_assert(u
->on_rescue
&& u
->restore_device
);
1561 /* There's no point in doing anything if the core is shut down anyway */
1562 if (c
->state
== PA_CORE_SHUTDOWN
)
1565 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1569 if (so
->direct_on_input
)
1575 if (!(name
= get_name(so
->proplist
, "source-output")))
1578 if ((e
= read_entry(u
, name
))) {
1580 if (e
->device_valid
) {
1583 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1585 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1586 pa_source_output_move_to(so
, d
, TRUE
);
1598 #define EXT_VERSION 1
1600 static void apply_entry(struct userdata
*u
, const char *name
, struct entry
*e
) {
1602 pa_source_output
*so
;
1609 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1613 if (!(n
= get_name(si
->proplist
, "sink-input")))
1616 if (!pa_streq(name
, n
)) {
1622 if (u
->restore_volume
&& e
->volume_valid
&& pa_sink_input_is_volume_writable(si
)) {
1626 pa_log_info("Restoring volume for sink input %s.", name
);
1627 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1628 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1631 if (u
->restore_muted
&& e
->muted_valid
) {
1632 pa_log_info("Restoring mute state for sink input %s.", name
);
1633 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1636 if (u
->restore_device
) {
1637 if (!e
->device_valid
) {
1638 if (si
->save_sink
) {
1639 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1640 /* If the device is not valid we should make sure the
1641 save flag is cleared as the user may have specifically
1642 removed the sink element from the rule. */
1643 si
->save_sink
= FALSE
;
1644 /* This is cheating a bit. The sink input itself has not changed
1645 but the rules governing it's routing have, so we fire this event
1646 such that other routing modules (e.g. module-device-manager)
1647 will pick up the change and reapply their routing */
1648 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1650 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1651 pa_log_info("Restoring device for stream %s.", name
);
1652 pa_sink_input_move_to(si
, s
, TRUE
);
1657 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1661 if (!(n
= get_name(so
->proplist
, "source-output")))
1664 if (!pa_streq(name
, n
)) {
1670 if (u
->restore_device
) {
1671 if (!e
->device_valid
) {
1672 if (so
->save_source
) {
1673 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1674 /* If the device is not valid we should make sure the
1675 save flag is cleared as the user may have specifically
1676 removed the source element from the rule. */
1677 so
->save_source
= FALSE
;
1678 /* This is cheating a bit. The source output itself has not changed
1679 but the rules governing it's routing have, so we fire this event
1680 such that other routing modules (e.g. module-device-manager)
1681 will pick up the change and reapply their routing */
1682 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1684 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1685 pa_log_info("Restoring device for stream %s.", name
);
1686 pa_source_output_move_to(so
, s
, TRUE
);
1693 static void dump_database(struct userdata
*u
) {
1697 done
= !pa_database_first(u
->database
, &key
, NULL
);
1704 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1706 name
= pa_xstrndup(key
.data
, key
.size
);
1707 pa_datum_free(&key
);
1709 if ((e
= read_entry(u
, name
))) {
1711 pa_log("name=%s", name
);
1712 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1713 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1714 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1715 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1726 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1729 pa_tagstruct
*reply
= NULL
;
1738 if (pa_tagstruct_getu32(t
, &command
) < 0)
1741 reply
= pa_tagstruct_new(NULL
, 0);
1742 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1743 pa_tagstruct_putu32(reply
, tag
);
1746 case SUBCOMMAND_TEST
: {
1747 if (!pa_tagstruct_eof(t
))
1750 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1754 case SUBCOMMAND_READ
: {
1758 if (!pa_tagstruct_eof(t
))
1761 done
= !pa_database_first(u
->database
, &key
, NULL
);
1768 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1770 name
= pa_xstrndup(key
.data
, key
.size
);
1771 pa_datum_free(&key
);
1773 if ((e
= read_entry(u
, name
))) {
1777 pa_tagstruct_puts(reply
, name
);
1778 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1779 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1780 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1781 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1794 case SUBCOMMAND_WRITE
: {
1796 pa_bool_t apply_immediately
= FALSE
;
1798 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1799 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1802 if (mode
!= PA_UPDATE_MERGE
&&
1803 mode
!= PA_UPDATE_REPLACE
&&
1804 mode
!= PA_UPDATE_SET
)
1807 if (mode
== PA_UPDATE_SET
) {
1809 struct dbus_entry
*de
;
1812 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
1813 send_entry_removed_signal(de
);
1814 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
1817 pa_database_clear(u
->database
);
1820 while (!pa_tagstruct_eof(t
)) {
1821 const char *name
, *device
;
1830 entry
.version
= ENTRY_VERSION
;
1832 if (pa_tagstruct_gets(t
, &name
) < 0 ||
1833 pa_tagstruct_get_channel_map(t
, &entry
.channel_map
) ||
1834 pa_tagstruct_get_cvolume(t
, &entry
.volume
) < 0 ||
1835 pa_tagstruct_gets(t
, &device
) < 0 ||
1836 pa_tagstruct_get_boolean(t
, &muted
) < 0)
1839 if (!name
|| !*name
)
1842 entry
.volume_valid
= entry
.volume
.channels
> 0;
1844 if (entry
.volume_valid
)
1845 if (!pa_cvolume_compatible_with_channel_map(&entry
.volume
, &entry
.channel_map
))
1848 entry
.muted
= muted
;
1849 entry
.muted_valid
= TRUE
;
1852 pa_strlcpy(entry
.device
, device
, sizeof(entry
.device
));
1853 entry
.device_valid
= !!entry
.device
[0];
1855 if (entry
.device_valid
&&
1856 !pa_namereg_is_valid_name(entry
.device
))
1860 old
= read_entry(u
, name
);
1863 key
.data
= (char*) name
;
1864 key
.size
= strlen(name
);
1867 data
.size
= sizeof(entry
);
1869 pa_log_debug("Client %s changes entry %s.",
1870 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
1873 if (pa_database_set(u
->database
, &key
, &data
, mode
== PA_UPDATE_REPLACE
) == 0) {
1875 struct dbus_entry
*de
;
1878 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1880 if ((old
->device_valid
!= entry
.device_valid
)
1881 || (entry
.device_valid
&& !pa_streq(entry
.device
, old
->device
)))
1882 send_device_updated_signal(de
, &entry
);
1884 if ((old
->volume_valid
!= entry
.volume_valid
)
1885 || (entry
.volume_valid
&& (!pa_cvolume_equal(&entry
.volume
, &old
->volume
)
1886 || !pa_channel_map_equal(&entry
.channel_map
, &old
->channel_map
))))
1887 send_volume_updated_signal(de
, &entry
);
1889 if (!old
->muted_valid
|| (entry
.muted
!= old
->muted
))
1890 send_mute_updated_signal(de
, &entry
);
1893 de
= dbus_entry_new(u
, name
);
1894 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1895 send_new_entry_signal(de
);
1899 if (apply_immediately
)
1900 apply_entry(u
, name
, &entry
);
1914 case SUBCOMMAND_DELETE
:
1916 while (!pa_tagstruct_eof(t
)) {
1920 struct dbus_entry
*de
;
1923 if (pa_tagstruct_gets(t
, &name
) < 0)
1927 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
1928 send_entry_removed_signal(de
);
1929 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
1933 key
.data
= (char*) name
;
1934 key
.size
= strlen(name
);
1936 pa_database_unset(u
->database
, &key
);
1943 case SUBCOMMAND_SUBSCRIBE
: {
1947 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
1948 !pa_tagstruct_eof(t
))
1952 pa_idxset_put(u
->subscribed
, c
, NULL
);
1954 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
1963 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
1969 pa_tagstruct_free(reply
);
1974 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
1979 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
1983 int pa__init(pa_module
*m
) {
1984 pa_modargs
*ma
= NULL
;
1988 pa_source_output
*so
;
1990 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
1998 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
1999 pa_log("Failed to parse module arguments");
2003 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2004 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2005 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2006 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2007 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2008 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2012 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2013 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2015 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2018 u
->restore_device
= restore_device
;
2019 u
->restore_volume
= restore_volume
;
2020 u
->restore_muted
= restore_muted
;
2021 u
->on_hotplug
= on_hotplug
;
2022 u
->on_rescue
= on_rescue
;
2023 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2025 u
->protocol
= pa_native_protocol_get(m
->core
);
2026 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2028 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
);
2030 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2032 if (restore_device
) {
2033 /* A little bit earlier than module-intended-roles ... */
2034 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
);
2035 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
);
2038 if (restore_device
&& on_hotplug
) {
2039 /* A little bit earlier than module-intended-roles ... */
2040 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
);
2041 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
);
2044 if (restore_device
&& on_rescue
) {
2045 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2046 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
);
2047 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
);
2050 if (restore_volume
|| restore_muted
)
2051 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
);
2053 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2056 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2057 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2062 pa_log_info("Successfully opened database file '%s'.", fname
);
2066 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2067 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2069 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2070 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2072 /* Create the initial dbus entries. */
2073 done
= !pa_database_first(u
->database
, &key
, NULL
);
2077 struct dbus_entry
*de
;
2080 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2082 name
= pa_xstrndup(key
.data
, key
.size
);
2083 pa_datum_free(&key
);
2085 /* Use read_entry() for checking that the entry is valid. */
2086 if ((e
= read_entry(u
, name
))) {
2087 de
= dbus_entry_new(u
, name
);
2088 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2098 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2099 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2101 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2102 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2104 pa_modargs_free(ma
);
2111 pa_modargs_free(ma
);
2117 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2118 struct dbus_entry
*de
= p
;
2122 dbus_entry_free(de
);
2126 void pa__done(pa_module
*m
) {
2131 if (!(u
= m
->userdata
))
2135 if (u
->dbus_protocol
) {
2136 pa_assert(u
->dbus_entries
);
2138 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2139 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2141 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2143 pa_dbus_protocol_unref(u
->dbus_protocol
);
2147 if (u
->subscription
)
2148 pa_subscription_free(u
->subscription
);
2150 if (u
->sink_input_new_hook_slot
)
2151 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2152 if (u
->sink_input_fixate_hook_slot
)
2153 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2154 if (u
->source_output_new_hook_slot
)
2155 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2157 if (u
->sink_put_hook_slot
)
2158 pa_hook_slot_free(u
->sink_put_hook_slot
);
2159 if (u
->source_put_hook_slot
)
2160 pa_hook_slot_free(u
->source_put_hook_slot
);
2162 if (u
->sink_unlink_hook_slot
)
2163 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2164 if (u
->source_unlink_hook_slot
)
2165 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2167 if (u
->connection_unlink_hook_slot
)
2168 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2170 if (u
->save_time_event
)
2171 u
->core
->mainloop
->time_free(u
->save_time_event
);
2174 pa_database_close(u
->database
);
2177 pa_native_protocol_remove_ext(u
->protocol
, m
);
2178 pa_native_protocol_unref(u
->protocol
);
2182 pa_idxset_free(u
->subscribed
, NULL
, NULL
);