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>
54 #include <pulsecore/tagstruct.h>
57 #include <pulsecore/dbus-util.h>
58 #include <pulsecore/protocol-dbus.h>
61 #include "module-stream-restore-symdef.h"
63 PA_MODULE_AUTHOR("Lennart Poettering");
64 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute/device state of streams");
65 PA_MODULE_VERSION(PACKAGE_VERSION
);
66 PA_MODULE_LOAD_ONCE(TRUE
);
68 "restore_device=<Save/restore sinks/sources?> "
69 "restore_volume=<Save/restore volumes?> "
70 "restore_muted=<Save/restore muted states?> "
71 "on_hotplug=<When new device becomes available, recheck streams?> "
72 "on_rescue=<When device becomes unavailable, recheck streams?>");
74 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
75 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
77 static const char* const valid_modargs
[] = {
89 pa_subscription
*subscription
;
91 *sink_input_new_hook_slot
,
92 *sink_input_fixate_hook_slot
,
93 *source_output_new_hook_slot
,
95 *source_put_hook_slot
,
96 *sink_unlink_hook_slot
,
97 *source_unlink_hook_slot
,
98 *connection_unlink_hook_slot
;
99 pa_time_event
*save_time_event
;
100 pa_database
* database
;
102 pa_bool_t restore_device
:1;
103 pa_bool_t restore_volume
:1;
104 pa_bool_t restore_muted
:1;
105 pa_bool_t on_hotplug
:1;
106 pa_bool_t on_rescue
:1;
108 pa_native_protocol
*protocol
;
109 pa_idxset
*subscribed
;
112 pa_dbus_protocol
*dbus_protocol
;
113 pa_hashmap
*dbus_entries
;
114 uint32_t next_index
; /* For generating object paths for entries. */
118 #define ENTRY_VERSION 4
122 pa_bool_t muted_valid
, volume_valid
, device_valid
, card_valid
;
124 pa_channel_map channel_map
;
135 SUBCOMMAND_SUBSCRIBE
,
140 static struct entry
* entry_new(void);
141 static void entry_free(struct entry
*e
);
142 static struct entry
*entry_read(struct userdata
*u
, const char *name
);
143 static pa_bool_t
entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, pa_bool_t replace
);
144 static struct entry
* entry_copy(const struct entry
*e
);
145 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
);
146 static void trigger_save(struct userdata
*u
);
150 #define OBJECT_PATH "/org/pulseaudio/stream_restore1"
151 #define ENTRY_OBJECT_NAME "entry"
152 #define INTERFACE_STREAM_RESTORE "org.PulseAudio.Ext.StreamRestore1"
153 #define INTERFACE_ENTRY INTERFACE_STREAM_RESTORE ".RestoreEntry"
155 #define DBUS_INTERFACE_REVISION 0
158 struct userdata
*userdata
;
165 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
166 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
168 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
170 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
171 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
173 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
174 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
175 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
176 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
177 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
178 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
179 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
180 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
182 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
184 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
186 enum property_handler_index
{
187 PROPERTY_HANDLER_INTERFACE_REVISION
,
188 PROPERTY_HANDLER_ENTRIES
,
192 enum entry_property_handler_index
{
193 ENTRY_PROPERTY_HANDLER_INDEX
,
194 ENTRY_PROPERTY_HANDLER_NAME
,
195 ENTRY_PROPERTY_HANDLER_DEVICE
,
196 ENTRY_PROPERTY_HANDLER_VOLUME
,
197 ENTRY_PROPERTY_HANDLER_MUTE
,
198 ENTRY_PROPERTY_HANDLER_MAX
201 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
202 [PROPERTY_HANDLER_INTERFACE_REVISION
] = { .property_name
= "InterfaceRevision", .type
= "u", .get_cb
= handle_get_interface_revision
, .set_cb
= NULL
},
203 [PROPERTY_HANDLER_ENTRIES
] = { .property_name
= "Entries", .type
= "ao", .get_cb
= handle_get_entries
, .set_cb
= NULL
}
206 static pa_dbus_property_handler entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MAX
] = {
207 [ENTRY_PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_entry_get_index
, .set_cb
= NULL
},
208 [ENTRY_PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_entry_get_name
, .set_cb
= NULL
},
209 [ENTRY_PROPERTY_HANDLER_DEVICE
] = { .property_name
= "Device", .type
= "s", .get_cb
= handle_entry_get_device
, .set_cb
= handle_entry_set_device
},
210 [ENTRY_PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "a(uu)", .get_cb
= handle_entry_get_volume
, .set_cb
= handle_entry_set_volume
},
211 [ENTRY_PROPERTY_HANDLER_MUTE
] = { .property_name
= "Mute", .type
= "b", .get_cb
= handle_entry_get_mute
, .set_cb
= handle_entry_set_mute
}
214 enum method_handler_index
{
215 METHOD_HANDLER_ADD_ENTRY
,
216 METHOD_HANDLER_GET_ENTRY_BY_NAME
,
220 enum entry_method_handler_index
{
221 ENTRY_METHOD_HANDLER_REMOVE
,
222 ENTRY_METHOD_HANDLER_MAX
225 static pa_dbus_arg_info add_entry_args
[] = { { "name", "s", "in" },
226 { "device", "s", "in" },
227 { "volume", "a(uu)", "in" },
228 { "mute", "b", "in" },
229 { "entry", "o", "out" } };
230 static pa_dbus_arg_info get_entry_by_name_args
[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
232 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
233 [METHOD_HANDLER_ADD_ENTRY
] = {
234 .method_name
= "AddEntry",
235 .arguments
= add_entry_args
,
236 .n_arguments
= sizeof(add_entry_args
) / sizeof(pa_dbus_arg_info
),
237 .receive_cb
= handle_add_entry
},
238 [METHOD_HANDLER_GET_ENTRY_BY_NAME
] = {
239 .method_name
= "GetEntryByName",
240 .arguments
= get_entry_by_name_args
,
241 .n_arguments
= sizeof(get_entry_by_name_args
) / sizeof(pa_dbus_arg_info
),
242 .receive_cb
= handle_get_entry_by_name
}
245 static pa_dbus_method_handler entry_method_handlers
[ENTRY_METHOD_HANDLER_MAX
] = {
246 [ENTRY_METHOD_HANDLER_REMOVE
] = {
247 .method_name
= "Remove",
250 .receive_cb
= handle_entry_remove
}
255 SIGNAL_ENTRY_REMOVED
,
259 enum entry_signal_index
{
260 ENTRY_SIGNAL_DEVICE_UPDATED
,
261 ENTRY_SIGNAL_VOLUME_UPDATED
,
262 ENTRY_SIGNAL_MUTE_UPDATED
,
266 static pa_dbus_arg_info new_entry_args
[] = { { "entry", "o", NULL
} };
267 static pa_dbus_arg_info entry_removed_args
[] = { { "entry", "o", NULL
} };
269 static pa_dbus_arg_info entry_device_updated_args
[] = { { "device", "s", NULL
} };
270 static pa_dbus_arg_info entry_volume_updated_args
[] = { { "volume", "a(uu)", NULL
} };
271 static pa_dbus_arg_info entry_mute_updated_args
[] = { { "muted", "b", NULL
} };
273 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
274 [SIGNAL_NEW_ENTRY
] = { .name
= "NewEntry", .arguments
= new_entry_args
, .n_arguments
= 1 },
275 [SIGNAL_ENTRY_REMOVED
] = { .name
= "EntryRemoved", .arguments
= entry_removed_args
, .n_arguments
= 1 }
278 static pa_dbus_signal_info entry_signals
[ENTRY_SIGNAL_MAX
] = {
279 [ENTRY_SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= entry_device_updated_args
, .n_arguments
= 1 },
280 [ENTRY_SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= entry_volume_updated_args
, .n_arguments
= 1 },
281 [ENTRY_SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= entry_mute_updated_args
, .n_arguments
= 1 }
284 static pa_dbus_interface_info stream_restore_interface_info
= {
285 .name
= INTERFACE_STREAM_RESTORE
,
286 .method_handlers
= method_handlers
,
287 .n_method_handlers
= METHOD_HANDLER_MAX
,
288 .property_handlers
= property_handlers
,
289 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
290 .get_all_properties_cb
= handle_get_all
,
292 .n_signals
= SIGNAL_MAX
295 static pa_dbus_interface_info entry_interface_info
= {
296 .name
= INTERFACE_ENTRY
,
297 .method_handlers
= entry_method_handlers
,
298 .n_method_handlers
= ENTRY_METHOD_HANDLER_MAX
,
299 .property_handlers
= entry_property_handlers
,
300 .n_property_handlers
= ENTRY_PROPERTY_HANDLER_MAX
,
301 .get_all_properties_cb
= handle_entry_get_all
,
302 .signals
= entry_signals
,
303 .n_signals
= ENTRY_SIGNAL_MAX
306 static struct dbus_entry
*dbus_entry_new(struct userdata
*u
, const char *entry_name
) {
307 struct dbus_entry
*de
;
310 pa_assert(entry_name
);
311 pa_assert(*entry_name
);
313 de
= pa_xnew(struct dbus_entry
, 1);
315 de
->entry_name
= pa_xstrdup(entry_name
);
316 de
->index
= u
->next_index
++;
317 de
->object_path
= pa_sprintf_malloc("%s/%s%u", OBJECT_PATH
, ENTRY_OBJECT_NAME
, de
->index
);
319 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, de
->object_path
, &entry_interface_info
, de
) >= 0);
324 static void dbus_entry_free(struct dbus_entry
*de
) {
327 pa_assert_se(pa_dbus_protocol_remove_interface(de
->userdata
->dbus_protocol
, de
->object_path
, entry_interface_info
.name
) >= 0);
329 pa_xfree(de
->entry_name
);
330 pa_xfree(de
->object_path
);
333 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
334 * are a channel position and a volume value, respectively. The result is
335 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
336 * element. If the data is invalid, an error reply is sent and a negative
337 * number is returned. In case of a failure we make no guarantees about the
338 * state of map and vol. In case of an empty array the channels field of both
339 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
340 * before returning. */
341 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
342 DBusMessageIter array_iter
;
343 DBusMessageIter struct_iter
;
348 pa_assert(pa_streq(dbus_message_iter_get_signature(iter
), "a(uu)"));
352 pa_channel_map_init(map
);
353 pa_cvolume_init(vol
);
358 dbus_message_iter_recurse(iter
, &array_iter
);
360 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
361 dbus_uint32_t chan_pos
;
362 dbus_uint32_t chan_vol
;
364 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
366 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
368 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
369 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
373 pa_assert_se(dbus_message_iter_next(&struct_iter
));
374 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
376 if (!PA_VOLUME_IS_VALID(chan_vol
)) {
377 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
381 if (map
->channels
< PA_CHANNELS_MAX
) {
382 map
->map
[map
->channels
] = chan_pos
;
383 vol
->values
[map
->channels
] = chan_vol
;
388 dbus_message_iter_next(&array_iter
);
391 if (map
->channels
> PA_CHANNELS_MAX
) {
392 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
396 dbus_message_iter_next(iter
);
401 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
402 DBusMessageIter array_iter
;
403 DBusMessageIter struct_iter
;
409 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
411 if (!e
->volume_valid
) {
412 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
416 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
417 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
419 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
420 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
422 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
425 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
428 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
429 DBusMessageIter variant_iter
;
434 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
436 append_volume(&variant_iter
, e
);
438 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
441 static void send_new_entry_signal(struct dbus_entry
*entry
) {
442 DBusMessage
*signal_msg
;
446 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
447 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
448 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
449 dbus_message_unref(signal_msg
);
452 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
453 DBusMessage
*signal_msg
;
457 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
458 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
459 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
460 dbus_message_unref(signal_msg
);
463 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
464 DBusMessage
*signal_msg
;
470 device
= e
->device_valid
? e
->device
: "";
472 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
473 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
474 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
475 dbus_message_unref(signal_msg
);
478 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
479 DBusMessage
*signal_msg
;
480 DBusMessageIter msg_iter
;
485 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
486 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
487 append_volume(&msg_iter
, e
);
488 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
489 dbus_message_unref(signal_msg
);
492 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
493 DBusMessage
*signal_msg
;
499 pa_assert(e
->muted_valid
);
503 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
504 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
505 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
506 dbus_message_unref(signal_msg
);
509 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
510 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
515 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
518 /* The caller frees the array, but not the strings. */
519 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
520 const char **entries
;
523 struct dbus_entry
*de
;
528 *n
= pa_hashmap_size(u
->dbus_entries
);
533 entries
= pa_xnew(const char *, *n
);
535 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
)
536 entries
[i
++] = de
->object_path
;
541 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
542 struct userdata
*u
= userdata
;
543 const char **entries
;
550 entries
= get_entries(u
, &n
);
552 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
557 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
558 struct userdata
*u
= userdata
;
559 DBusMessage
*reply
= NULL
;
560 DBusMessageIter msg_iter
;
561 DBusMessageIter dict_iter
;
562 dbus_uint32_t interface_revision
;
563 const char **entries
;
570 interface_revision
= DBUS_INTERFACE_REVISION
;
571 entries
= get_entries(u
, &n_entries
);
573 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
575 dbus_message_iter_init_append(reply
, &msg_iter
);
576 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
578 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
579 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
581 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
583 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
585 dbus_message_unref(reply
);
590 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
591 struct userdata
*u
= userdata
;
592 DBusMessageIter msg_iter
;
593 const char *name
= NULL
;
594 const char *device
= NULL
;
597 dbus_bool_t muted
= FALSE
;
598 dbus_bool_t apply_immediately
= FALSE
;
599 struct dbus_entry
*dbus_entry
= NULL
;
600 struct entry
*e
= NULL
;
606 pa_assert_se(dbus_message_iter_init(msg
, &msg_iter
));
607 dbus_message_iter_get_basic(&msg_iter
, &name
);
609 pa_assert_se(dbus_message_iter_next(&msg_iter
));
610 dbus_message_iter_get_basic(&msg_iter
, &device
);
612 pa_assert_se(dbus_message_iter_next(&msg_iter
));
613 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
616 dbus_message_iter_get_basic(&msg_iter
, &muted
);
618 pa_assert_se(dbus_message_iter_next(&msg_iter
));
619 dbus_message_iter_get_basic(&msg_iter
, &apply_immediately
);
622 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
626 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
627 pa_bool_t mute_updated
= FALSE
;
628 pa_bool_t volume_updated
= FALSE
;
629 pa_bool_t device_updated
= FALSE
;
631 pa_assert_se(e
= entry_read(u
, name
));
632 mute_updated
= e
->muted
!= muted
;
634 e
->muted_valid
= TRUE
;
636 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
638 e
->channel_map
= map
;
639 e
->volume_valid
= !!map
.channels
;
641 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
643 e
->device
= pa_xstrdup(device
);
644 e
->device_valid
= !!device
[0];
647 send_mute_updated_signal(dbus_entry
, e
);
649 send_volume_updated_signal(dbus_entry
, e
);
651 send_device_updated_signal(dbus_entry
, e
);
654 dbus_entry
= dbus_entry_new(u
, name
);
655 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) == 0);
658 e
->muted_valid
= TRUE
;
659 e
->volume_valid
= !!map
.channels
;
660 e
->device_valid
= !!device
[0];
663 e
->channel_map
= map
;
664 e
->device
= pa_xstrdup(device
);
666 send_new_entry_signal(dbus_entry
);
669 pa_assert_se(entry_write(u
, name
, e
, TRUE
));
671 if (apply_immediately
)
672 entry_apply(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
= entry_read(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
= entry_read(de
->userdata
, de
->entry_name
));
753 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
757 e
->device
= pa_xstrdup(device
);
758 e
->device_valid
= !!device
[0];
760 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
762 entry_apply(de
->userdata
, de
->entry_name
, e
);
763 send_device_updated_signal(de
, e
);
764 trigger_save(de
->userdata
);
767 pa_dbus_send_empty_reply(conn
, msg
);
772 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
773 struct dbus_entry
*de
= userdata
;
775 DBusMessageIter msg_iter
;
782 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
784 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
786 dbus_message_iter_init_append(reply
, &msg_iter
);
787 append_volume_variant(&msg_iter
, e
);
789 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
794 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
795 struct dbus_entry
*de
= userdata
;
798 struct entry
*e
= NULL
;
799 pa_bool_t updated
= FALSE
;
806 if (get_volume_arg(conn
, msg
, iter
, &map
, &vol
) < 0)
809 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
811 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
815 e
->channel_map
= map
;
816 e
->volume_valid
= !!map
.channels
;
818 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
820 entry_apply(de
->userdata
, de
->entry_name
, e
);
821 send_volume_updated_signal(de
, e
);
822 trigger_save(de
->userdata
);
825 pa_dbus_send_empty_reply(conn
, msg
);
830 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
831 struct dbus_entry
*de
= userdata
;
839 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
841 mute
= e
->muted_valid
? e
->muted
: FALSE
;
843 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &mute
);
848 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
849 struct dbus_entry
*de
= userdata
;
859 dbus_message_iter_get_basic(iter
, &mute
);
861 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
863 updated
= !e
->muted_valid
|| e
->muted
!= mute
;
867 e
->muted_valid
= TRUE
;
869 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
871 entry_apply(de
->userdata
, de
->entry_name
, e
);
872 send_mute_updated_signal(de
, e
);
873 trigger_save(de
->userdata
);
876 pa_dbus_send_empty_reply(conn
, msg
);
881 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
882 struct dbus_entry
*de
= userdata
;
884 DBusMessage
*reply
= NULL
;
885 DBusMessageIter msg_iter
;
886 DBusMessageIter dict_iter
;
887 DBusMessageIter dict_entry_iter
;
895 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
897 device
= e
->device_valid
? e
->device
: "";
898 mute
= e
->muted_valid
? e
->muted
: FALSE
;
900 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
902 dbus_message_iter_init_append(reply
, &msg_iter
);
903 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
905 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
906 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
907 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
909 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
911 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
912 append_volume_variant(&dict_entry_iter
, e
);
914 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
916 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &mute
);
918 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
920 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
922 dbus_message_unref(reply
);
927 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
928 struct dbus_entry
*de
= userdata
;
935 key
.data
= de
->entry_name
;
936 key
.size
= strlen(de
->entry_name
);
938 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
940 send_entry_removed_signal(de
);
941 trigger_save(de
->userdata
);
943 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
946 pa_dbus_send_empty_reply(conn
, msg
);
949 #endif /* HAVE_DBUS */
951 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
952 struct userdata
*u
= userdata
;
958 pa_assert(e
== u
->save_time_event
);
959 u
->core
->mainloop
->time_free(u
->save_time_event
);
960 u
->save_time_event
= NULL
;
962 pa_database_sync(u
->database
);
963 pa_log_info("Synced.");
966 static char *get_name(pa_proplist
*p
, const char *prefix
) {
973 if ((r
= pa_proplist_gets(p
, IDENTIFICATION_PROPERTY
)))
974 return pa_xstrdup(r
);
976 if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_ROLE
)))
977 t
= pa_sprintf_malloc("%s-by-media-role:%s", prefix
, r
);
978 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_ID
)))
979 t
= pa_sprintf_malloc("%s-by-application-id:%s", prefix
, r
);
980 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_NAME
)))
981 t
= pa_sprintf_malloc("%s-by-application-name:%s", prefix
, r
);
982 else if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
)))
983 t
= pa_sprintf_malloc("%s-by-media-name:%s", prefix
, r
);
985 t
= pa_sprintf_malloc("%s-fallback:%s", prefix
, r
);
987 pa_proplist_sets(p
, IDENTIFICATION_PROPERTY
, t
);
991 static struct entry
* entry_new(void) {
992 struct entry
*r
= pa_xnew0(struct entry
, 1);
993 r
->version
= ENTRY_VERSION
;
997 static void entry_free(struct entry
* e
) {
1000 pa_xfree(e
->device
);
1005 static struct entry
*entry_read(struct userdata
*u
, const char *name
) {
1007 struct entry
*e
= NULL
;
1008 pa_tagstruct
*t
= NULL
;
1009 const char *device
, *card
;
1014 key
.data
= (char*) name
;
1015 key
.size
= strlen(name
);
1019 if (!pa_database_get(u
->database
, &key
, &data
))
1022 t
= pa_tagstruct_new(data
.data
, data
.size
);
1025 if (pa_tagstruct_getu8(t
, &e
->version
) < 0 ||
1026 e
->version
> ENTRY_VERSION
||
1027 pa_tagstruct_get_boolean(t
, &e
->volume_valid
) < 0 ||
1028 pa_tagstruct_get_channel_map(t
, &e
->channel_map
) < 0 ||
1029 pa_tagstruct_get_cvolume(t
, &e
->volume
) < 0 ||
1030 pa_tagstruct_get_boolean(t
, &e
->muted_valid
) < 0 ||
1031 pa_tagstruct_get_boolean(t
, &e
->muted
) < 0 ||
1032 pa_tagstruct_get_boolean(t
, &e
->device_valid
) < 0 ||
1033 pa_tagstruct_gets(t
, &device
) < 0 ||
1034 pa_tagstruct_get_boolean(t
, &e
->card_valid
) < 0 ||
1035 pa_tagstruct_gets(t
, &card
) < 0) {
1040 e
->device
= pa_xstrdup(device
);
1041 e
->card
= pa_xstrdup(card
);
1043 if (!pa_tagstruct_eof(t
))
1046 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1047 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1051 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1052 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1056 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1057 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1061 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1062 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1066 pa_tagstruct_free(t
);
1067 pa_datum_free(&data
);
1073 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name
);
1078 pa_tagstruct_free(t
);
1079 pa_datum_free(&data
);
1083 static pa_bool_t
entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, pa_bool_t replace
) {
1092 t
= pa_tagstruct_new(NULL
, 0);
1093 pa_tagstruct_putu8(t
, e
->version
);
1094 pa_tagstruct_put_boolean(t
, e
->volume_valid
);
1095 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
1096 pa_tagstruct_put_cvolume(t
, &e
->volume
);
1097 pa_tagstruct_put_boolean(t
, e
->muted_valid
);
1098 pa_tagstruct_put_boolean(t
, e
->muted
);
1099 pa_tagstruct_put_boolean(t
, e
->device_valid
);
1100 pa_tagstruct_puts(t
, e
->device
);
1101 pa_tagstruct_put_boolean(t
, e
->card_valid
);
1102 pa_tagstruct_puts(t
, e
->card
);
1104 key
.data
= (char *) name
;
1105 key
.size
= strlen(name
);
1107 data
.data
= (void*)pa_tagstruct_data(t
, &data
.size
);
1109 r
= (pa_database_set(u
->database
, &key
, &data
, replace
) == 0);
1111 pa_tagstruct_free(t
);
1116 static struct entry
* entry_copy(const struct entry
*e
) {
1122 r
->device
= pa_xstrdup(e
->device
);
1123 r
->card
= pa_xstrdup(e
->card
);
1127 static void trigger_save(struct userdata
*u
) {
1128 pa_native_connection
*c
;
1131 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1134 t
= pa_tagstruct_new(NULL
, 0);
1135 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1136 pa_tagstruct_putu32(t
, 0);
1137 pa_tagstruct_putu32(t
, u
->module
->index
);
1138 pa_tagstruct_puts(t
, u
->module
->name
);
1139 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1141 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1144 if (u
->save_time_event
)
1147 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1150 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1156 if (a
->device_valid
!= b
->device_valid
||
1157 (a
->device_valid
&& !pa_streq(a
->device
, b
->device
)))
1160 if (a
->card_valid
!= b
->card_valid
||
1161 (a
->card_valid
&& !pa_streq(a
->card
, b
->card
)))
1164 if (a
->muted_valid
!= b
->muted_valid
||
1165 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1169 if (a
->volume_valid
!= b
->volume_valid
||
1170 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1176 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1177 struct userdata
*u
= userdata
;
1178 struct entry
*entry
, *old
= NULL
;
1181 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1182 * clutter these are defined here unconditionally. */
1183 pa_bool_t created_new_entry
= TRUE
;
1184 pa_bool_t device_updated
= FALSE
;
1185 pa_bool_t volume_updated
= FALSE
;
1186 pa_bool_t mute_updated
= FALSE
;
1189 struct dbus_entry
*de
= NULL
;
1195 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1196 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1197 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1198 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1201 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1202 pa_sink_input
*sink_input
;
1204 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1207 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1210 if ((old
= entry_read(u
, name
))) {
1211 entry
= entry_copy(old
);
1212 created_new_entry
= FALSE
;
1214 entry
= entry_new();
1216 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1217 pa_assert(sink_input
->volume_writable
);
1219 entry
->channel_map
= sink_input
->channel_map
;
1220 pa_sink_input_get_volume(sink_input
, &entry
->volume
, FALSE
);
1221 entry
->volume_valid
= TRUE
;
1223 volume_updated
= !created_new_entry
1224 && (!old
->volume_valid
1225 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1226 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1229 if (sink_input
->save_muted
) {
1230 entry
->muted
= pa_sink_input_get_mute(sink_input
);
1231 entry
->muted_valid
= TRUE
;
1233 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1236 if (sink_input
->save_sink
) {
1237 pa_xfree(entry
->device
);
1238 entry
->device
= pa_xstrdup(sink_input
->sink
->name
);
1239 entry
->device_valid
= TRUE
;
1241 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1242 if (sink_input
->sink
->card
) {
1243 pa_xfree(entry
->card
);
1244 entry
->card
= pa_xstrdup(sink_input
->sink
->card
->name
);
1245 entry
->card_valid
= TRUE
;
1250 pa_source_output
*source_output
;
1252 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1254 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1257 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1260 if ((old
= entry_read(u
, name
))) {
1261 entry
= entry_copy(old
);
1262 created_new_entry
= FALSE
;
1264 entry
= entry_new();
1266 if (source_output
->save_source
) {
1267 pa_xfree(entry
->device
);
1268 entry
->device
= pa_xstrdup(source_output
->source
->name
);
1269 entry
->device_valid
= TRUE
;
1271 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1273 if (source_output
->source
->card
) {
1274 pa_xfree(entry
->card
);
1275 entry
->card
= pa_xstrdup(source_output
->source
->card
->name
);
1276 entry
->card_valid
= TRUE
;
1285 if (entries_equal(old
, entry
)) {
1295 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1297 if (entry_write(u
, name
, entry
, TRUE
))
1301 if (created_new_entry
) {
1302 de
= dbus_entry_new(u
, name
);
1303 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1304 send_new_entry_signal(de
);
1306 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1309 send_device_updated_signal(de
, entry
);
1311 send_volume_updated_signal(de
, entry
);
1313 send_mute_updated_signal(de
, entry
);
1321 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1326 pa_assert(new_data
);
1328 pa_assert(u
->restore_device
);
1330 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1334 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1335 else if ((e
= entry_read(u
, name
))) {
1338 if (e
->device_valid
)
1339 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1341 if (!s
&& e
->card_valid
) {
1344 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1345 s
= pa_idxset_first(card
->sinks
, NULL
);
1348 /* It might happen that a stream and a sink are set up at the
1349 same time, in which case we want to make sure we don't
1350 interfere with that */
1351 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1352 if (pa_sink_input_new_data_set_sink(new_data
, s
, TRUE
))
1353 pa_log_info("Restoring device for stream %s.", name
);
1363 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1368 pa_assert(new_data
);
1370 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1372 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1375 if ((e
= entry_read(u
, name
))) {
1377 if (u
->restore_volume
&& e
->volume_valid
) {
1378 if (!new_data
->volume_writable
)
1379 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1380 else if (new_data
->volume_is_set
)
1381 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1385 pa_log_info("Restoring volume for sink input %s.", name
);
1388 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1389 pa_sink_input_new_data_set_volume(new_data
, &v
);
1391 new_data
->volume_is_absolute
= FALSE
;
1392 new_data
->save_volume
= TRUE
;
1396 if (u
->restore_muted
&& e
->muted_valid
) {
1398 if (!new_data
->muted_is_set
) {
1399 pa_log_info("Restoring mute state for sink input %s.", name
);
1400 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1401 new_data
->save_muted
= TRUE
;
1403 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1414 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1419 pa_assert(new_data
);
1421 pa_assert(u
->restore_device
);
1423 if (new_data
->direct_on_input
)
1426 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1429 if (new_data
->source
)
1430 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1431 else if ((e
= entry_read(u
, name
))) {
1432 pa_source
*s
= NULL
;
1434 if (e
->device_valid
)
1435 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1437 if (!s
&& e
->card_valid
) {
1440 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1441 s
= pa_idxset_first(card
->sources
, NULL
);
1444 /* It might happen that a stream and a sink are set up at the
1445 same time, in which case we want to make sure we don't
1446 interfere with that */
1447 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1448 pa_log_info("Restoring device for stream %s.", name
);
1449 pa_source_output_new_data_set_source(new_data
, s
, TRUE
);
1460 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1467 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1469 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1473 if (si
->sink
== sink
)
1479 /* Skip this if it is already in the process of being moved
1484 /* It might happen that a stream and a sink are set up at the
1485 same time, in which case we want to make sure we don't
1486 interfere with that */
1487 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1490 if (!(name
= get_name(si
->proplist
, "sink-input")))
1493 if ((e
= entry_read(u
, name
))) {
1494 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1495 pa_sink_input_move_to(si
, sink
, TRUE
);
1506 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1507 pa_source_output
*so
;
1513 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1515 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1519 if (so
->source
== source
)
1522 if (so
->save_source
)
1525 if (so
->direct_on_input
)
1528 /* Skip this if it is already in the process of being moved anyway */
1532 /* It might happen that a stream and a source are set up at the
1533 same time, in which case we want to make sure we don't
1534 interfere with that */
1535 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1538 if (!(name
= get_name(so
->proplist
, "source-output")))
1541 if ((e
= entry_read(u
, name
))) {
1542 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1543 pa_source_output_move_to(so
, source
, TRUE
);
1554 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1561 pa_assert(u
->on_rescue
&& u
->restore_device
);
1563 /* There's no point in doing anything if the core is shut down anyway */
1564 if (c
->state
== PA_CORE_SHUTDOWN
)
1567 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1574 if (!(name
= get_name(si
->proplist
, "sink-input")))
1577 if ((e
= entry_read(u
, name
))) {
1579 if (e
->device_valid
) {
1582 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1584 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1585 pa_sink_input_move_to(si
, d
, TRUE
);
1597 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1598 pa_source_output
*so
;
1604 pa_assert(u
->on_rescue
&& u
->restore_device
);
1606 /* There's no point in doing anything if the core is shut down anyway */
1607 if (c
->state
== PA_CORE_SHUTDOWN
)
1610 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1614 if (so
->direct_on_input
)
1620 if (!(name
= get_name(so
->proplist
, "source-output")))
1623 if ((e
= entry_read(u
, name
))) {
1625 if (e
->device_valid
) {
1628 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1630 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1631 pa_source_output_move_to(so
, d
, TRUE
);
1643 #define EXT_VERSION 1
1645 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
) {
1647 pa_source_output
*so
;
1654 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1658 if (!(n
= get_name(si
->proplist
, "sink-input")))
1661 if (!pa_streq(name
, n
)) {
1667 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1671 pa_log_info("Restoring volume for sink input %s.", name
);
1672 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1673 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1676 if (u
->restore_muted
&& e
->muted_valid
) {
1677 pa_log_info("Restoring mute state for sink input %s.", name
);
1678 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1681 if (u
->restore_device
) {
1682 if (!e
->device_valid
) {
1683 if (si
->save_sink
) {
1684 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1685 /* If the device is not valid we should make sure the
1686 save flag is cleared as the user may have specifically
1687 removed the sink element from the rule. */
1688 si
->save_sink
= FALSE
;
1689 /* This is cheating a bit. The sink input itself has not changed
1690 but the rules governing it's routing have, so we fire this event
1691 such that other routing modules (e.g. module-device-manager)
1692 will pick up the change and reapply their routing */
1693 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1695 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1696 pa_log_info("Restoring device for stream %s.", name
);
1697 pa_sink_input_move_to(si
, s
, TRUE
);
1702 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1706 if (!(n
= get_name(so
->proplist
, "source-output")))
1709 if (!pa_streq(name
, n
)) {
1715 if (u
->restore_device
) {
1716 if (!e
->device_valid
) {
1717 if (so
->save_source
) {
1718 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1719 /* If the device is not valid we should make sure the
1720 save flag is cleared as the user may have specifically
1721 removed the source element from the rule. */
1722 so
->save_source
= FALSE
;
1723 /* This is cheating a bit. The source output itself has not changed
1724 but the rules governing it's routing have, so we fire this event
1725 such that other routing modules (e.g. module-device-manager)
1726 will pick up the change and reapply their routing */
1727 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1729 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1730 pa_log_info("Restoring device for stream %s.", name
);
1731 pa_source_output_move_to(so
, s
, TRUE
);
1738 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1742 done
= !pa_database_first(u
->database
, &key
, NULL
);
1749 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1751 name
= pa_xstrndup(key
.data
, key
.size
);
1752 pa_datum_free(&key
);
1754 if ((e
= entry_read(u
, name
))) {
1756 pa_log("name=%s", name
);
1757 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1758 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1759 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1760 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1771 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1774 pa_tagstruct
*reply
= NULL
;
1783 if (pa_tagstruct_getu32(t
, &command
) < 0)
1786 reply
= pa_tagstruct_new(NULL
, 0);
1787 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1788 pa_tagstruct_putu32(reply
, tag
);
1791 case SUBCOMMAND_TEST
: {
1792 if (!pa_tagstruct_eof(t
))
1795 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1799 case SUBCOMMAND_READ
: {
1803 if (!pa_tagstruct_eof(t
))
1806 done
= !pa_database_first(u
->database
, &key
, NULL
);
1813 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1815 name
= pa_xstrndup(key
.data
, key
.size
);
1816 pa_datum_free(&key
);
1818 if ((e
= entry_read(u
, name
))) {
1822 pa_tagstruct_puts(reply
, name
);
1823 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1824 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1825 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1826 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1839 case SUBCOMMAND_WRITE
: {
1841 pa_bool_t apply_immediately
= FALSE
;
1843 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1844 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1847 if (mode
!= PA_UPDATE_MERGE
&&
1848 mode
!= PA_UPDATE_REPLACE
&&
1849 mode
!= PA_UPDATE_SET
)
1852 if (mode
== PA_UPDATE_SET
) {
1854 struct dbus_entry
*de
;
1857 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
1858 send_entry_removed_signal(de
);
1859 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
1862 pa_database_clear(u
->database
);
1865 while (!pa_tagstruct_eof(t
)) {
1866 const char *name
, *device
;
1868 struct entry
*entry
;
1873 entry
= entry_new();
1875 if (pa_tagstruct_gets(t
, &name
) < 0 ||
1876 pa_tagstruct_get_channel_map(t
, &entry
->channel_map
) ||
1877 pa_tagstruct_get_cvolume(t
, &entry
->volume
) < 0 ||
1878 pa_tagstruct_gets(t
, &device
) < 0 ||
1879 pa_tagstruct_get_boolean(t
, &muted
) < 0)
1882 if (!name
|| !*name
) {
1887 entry
->volume_valid
= entry
->volume
.channels
> 0;
1889 if (entry
->volume_valid
)
1890 if (!pa_cvolume_compatible_with_channel_map(&entry
->volume
, &entry
->channel_map
)) {
1895 entry
->muted
= muted
;
1896 entry
->muted_valid
= TRUE
;
1898 entry
->device
= pa_xstrdup(device
);
1899 entry
->device_valid
= device
&& !!entry
->device
[0];
1901 if (entry
->device_valid
&& !pa_namereg_is_valid_name(entry
->device
)) {
1907 old
= entry_read(u
, name
);
1910 pa_log_debug("Client %s changes entry %s.",
1911 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
1914 if (entry_write(u
, name
, entry
, mode
== PA_UPDATE_REPLACE
)) {
1916 struct dbus_entry
*de
;
1919 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1921 if ((old
->device_valid
!= entry
->device_valid
)
1922 || (entry
->device_valid
&& !pa_streq(entry
->device
, old
->device
)))
1923 send_device_updated_signal(de
, entry
);
1925 if ((old
->volume_valid
!= entry
->volume_valid
)
1926 || (entry
->volume_valid
&& (!pa_cvolume_equal(&entry
->volume
, &old
->volume
)
1927 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
))))
1928 send_volume_updated_signal(de
, entry
);
1930 if (!old
->muted_valid
|| (entry
->muted
!= old
->muted
))
1931 send_mute_updated_signal(de
, entry
);
1934 de
= dbus_entry_new(u
, name
);
1935 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1936 send_new_entry_signal(de
);
1940 if (apply_immediately
)
1941 entry_apply(u
, name
, entry
);
1956 case SUBCOMMAND_DELETE
:
1958 while (!pa_tagstruct_eof(t
)) {
1962 struct dbus_entry
*de
;
1965 if (pa_tagstruct_gets(t
, &name
) < 0)
1969 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
1970 send_entry_removed_signal(de
);
1971 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
1975 key
.data
= (char*) name
;
1976 key
.size
= strlen(name
);
1978 pa_database_unset(u
->database
, &key
);
1985 case SUBCOMMAND_SUBSCRIBE
: {
1989 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
1990 !pa_tagstruct_eof(t
))
1994 pa_idxset_put(u
->subscribed
, c
, NULL
);
1996 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2005 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
2011 pa_tagstruct_free(reply
);
2016 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
2021 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2025 int pa__init(pa_module
*m
) {
2026 pa_modargs
*ma
= NULL
;
2030 pa_source_output
*so
;
2032 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
2040 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2041 pa_log("Failed to parse module arguments");
2045 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2046 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2047 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2048 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2049 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2050 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2054 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2055 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2057 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2060 u
->restore_device
= restore_device
;
2061 u
->restore_volume
= restore_volume
;
2062 u
->restore_muted
= restore_muted
;
2063 u
->on_hotplug
= on_hotplug
;
2064 u
->on_rescue
= on_rescue
;
2065 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2067 u
->protocol
= pa_native_protocol_get(m
->core
);
2068 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2070 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
);
2072 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2074 if (restore_device
) {
2075 /* A little bit earlier than module-intended-roles ... */
2076 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
);
2077 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
);
2080 if (restore_device
&& on_hotplug
) {
2081 /* A little bit earlier than module-intended-roles ... */
2082 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
);
2083 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
);
2086 if (restore_device
&& on_rescue
) {
2087 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2088 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
);
2089 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
);
2092 if (restore_volume
|| restore_muted
)
2093 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
);
2095 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2098 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2099 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2104 pa_log_info("Successfully opened database file '%s'.", fname
);
2108 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2109 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2111 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2112 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2114 /* Create the initial dbus entries. */
2115 done
= !pa_database_first(u
->database
, &key
, NULL
);
2119 struct dbus_entry
*de
;
2122 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2124 name
= pa_xstrndup(key
.data
, key
.size
);
2125 pa_datum_free(&key
);
2127 /* Use entry_read() for checking that the entry is valid. */
2128 if ((e
= entry_read(u
, name
))) {
2129 de
= dbus_entry_new(u
, name
);
2130 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2140 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2141 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2143 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2144 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2146 pa_modargs_free(ma
);
2153 pa_modargs_free(ma
);
2159 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2160 struct dbus_entry
*de
= p
;
2164 dbus_entry_free(de
);
2168 void pa__done(pa_module
*m
) {
2173 if (!(u
= m
->userdata
))
2177 if (u
->dbus_protocol
) {
2178 pa_assert(u
->dbus_entries
);
2180 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2181 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2183 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2185 pa_dbus_protocol_unref(u
->dbus_protocol
);
2189 if (u
->subscription
)
2190 pa_subscription_free(u
->subscription
);
2192 if (u
->sink_input_new_hook_slot
)
2193 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2194 if (u
->sink_input_fixate_hook_slot
)
2195 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2196 if (u
->source_output_new_hook_slot
)
2197 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2199 if (u
->sink_put_hook_slot
)
2200 pa_hook_slot_free(u
->sink_put_hook_slot
);
2201 if (u
->source_put_hook_slot
)
2202 pa_hook_slot_free(u
->source_put_hook_slot
);
2204 if (u
->sink_unlink_hook_slot
)
2205 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2206 if (u
->source_unlink_hook_slot
)
2207 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2209 if (u
->connection_unlink_hook_slot
)
2210 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2212 if (u
->save_time_event
)
2213 u
->core
->mainloop
->time_free(u
->save_time_event
);
2216 pa_database_close(u
->database
);
2219 pa_native_protocol_remove_ext(u
->protocol
, m
);
2220 pa_native_protocol_unref(u
->protocol
);
2224 pa_idxset_free(u
->subscribed
, NULL
, NULL
);