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 1
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 pa_bool_t
entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, pa_bool_t replace
) {
1014 t
= pa_tagstruct_new(NULL
, 0);
1015 pa_tagstruct_putu8(t
, e
->version
);
1016 pa_tagstruct_put_boolean(t
, e
->volume_valid
);
1017 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
1018 pa_tagstruct_put_cvolume(t
, &e
->volume
);
1019 pa_tagstruct_put_boolean(t
, e
->muted_valid
);
1020 pa_tagstruct_put_boolean(t
, e
->muted
);
1021 pa_tagstruct_put_boolean(t
, e
->device_valid
);
1022 pa_tagstruct_puts(t
, e
->device
);
1023 pa_tagstruct_put_boolean(t
, e
->card_valid
);
1024 pa_tagstruct_puts(t
, e
->card
);
1026 key
.data
= (char *) name
;
1027 key
.size
= strlen(name
);
1029 data
.data
= (void*)pa_tagstruct_data(t
, &data
.size
);
1031 r
= (pa_database_set(u
->database
, &key
, &data
, replace
) == 0);
1033 pa_tagstruct_free(t
);
1038 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1040 #define LEGACY_ENTRY_VERSION 3
1041 static struct entry
* legacy_entry_read(struct userdata
*u
, pa_datum
*data
) {
1042 struct legacy_entry
{
1044 pa_bool_t muted_valid
:1, volume_valid
:1, device_valid
:1, card_valid
:1;
1046 pa_channel_map channel_map
;
1048 char device
[PA_NAME_MAX
];
1049 char card
[PA_NAME_MAX
];
1051 struct legacy_entry
*le
;
1057 if (data
->size
!= sizeof(struct legacy_entry
)) {
1058 pa_log_debug("Size does not match.");
1062 le
= (struct legacy_entry
*)data
->data
;
1064 if (le
->version
!= LEGACY_ENTRY_VERSION
) {
1065 pa_log_debug("Version mismatch.");
1069 if (!memchr(le
->device
, 0, sizeof(le
->device
))) {
1070 pa_log_warn("Device has missing NUL byte.");
1074 if (!memchr(le
->card
, 0, sizeof(le
->card
))) {
1075 pa_log_warn("Card has missing NUL byte.");
1080 e
->card
= pa_xstrdup(le
->card
);
1085 static struct entry
*entry_read(struct userdata
*u
, const char *name
) {
1087 struct entry
*e
= NULL
;
1088 pa_tagstruct
*t
= NULL
;
1089 const char *device
, *card
;
1094 key
.data
= (char*) name
;
1095 key
.size
= strlen(name
);
1099 if (!pa_database_get(u
->database
, &key
, &data
))
1102 t
= pa_tagstruct_new(data
.data
, data
.size
);
1105 if (pa_tagstruct_getu8(t
, &e
->version
) < 0 ||
1106 e
->version
> ENTRY_VERSION
||
1107 pa_tagstruct_get_boolean(t
, &e
->volume_valid
) < 0 ||
1108 pa_tagstruct_get_channel_map(t
, &e
->channel_map
) < 0 ||
1109 pa_tagstruct_get_cvolume(t
, &e
->volume
) < 0 ||
1110 pa_tagstruct_get_boolean(t
, &e
->muted_valid
) < 0 ||
1111 pa_tagstruct_get_boolean(t
, &e
->muted
) < 0 ||
1112 pa_tagstruct_get_boolean(t
, &e
->device_valid
) < 0 ||
1113 pa_tagstruct_gets(t
, &device
) < 0 ||
1114 pa_tagstruct_get_boolean(t
, &e
->card_valid
) < 0 ||
1115 pa_tagstruct_gets(t
, &card
) < 0) {
1120 e
->device
= pa_xstrdup(device
);
1121 e
->card
= pa_xstrdup(card
);
1123 if (!pa_tagstruct_eof(t
))
1126 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1127 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1131 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1132 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1136 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1137 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1141 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1142 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1146 pa_tagstruct_free(t
);
1147 pa_datum_free(&data
);
1153 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name
);
1158 pa_tagstruct_free(t
);
1160 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1161 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name
);
1162 if ((e
= legacy_entry_read(u
, &data
))) {
1163 pa_log_debug("Success. Saving new format for key: %s", name
);
1164 if (entry_write(u
, name
, e
, TRUE
))
1166 pa_datum_free(&data
);
1169 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name
);
1172 pa_datum_free(&data
);
1176 static struct entry
* entry_copy(const struct entry
*e
) {
1182 r
->device
= pa_xstrdup(e
->device
);
1183 r
->card
= pa_xstrdup(e
->card
);
1187 static void trigger_save(struct userdata
*u
) {
1188 pa_native_connection
*c
;
1191 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1194 t
= pa_tagstruct_new(NULL
, 0);
1195 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1196 pa_tagstruct_putu32(t
, 0);
1197 pa_tagstruct_putu32(t
, u
->module
->index
);
1198 pa_tagstruct_puts(t
, u
->module
->name
);
1199 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1201 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1204 if (u
->save_time_event
)
1207 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1210 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1216 if (a
->device_valid
!= b
->device_valid
||
1217 (a
->device_valid
&& !pa_streq(a
->device
, b
->device
)))
1220 if (a
->card_valid
!= b
->card_valid
||
1221 (a
->card_valid
&& !pa_streq(a
->card
, b
->card
)))
1224 if (a
->muted_valid
!= b
->muted_valid
||
1225 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1229 if (a
->volume_valid
!= b
->volume_valid
||
1230 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1236 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1237 struct userdata
*u
= userdata
;
1238 struct entry
*entry
, *old
= NULL
;
1241 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1242 * clutter these are defined here unconditionally. */
1243 pa_bool_t created_new_entry
= TRUE
;
1244 pa_bool_t device_updated
= FALSE
;
1245 pa_bool_t volume_updated
= FALSE
;
1246 pa_bool_t mute_updated
= FALSE
;
1249 struct dbus_entry
*de
= NULL
;
1255 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1256 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1257 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1258 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1261 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1262 pa_sink_input
*sink_input
;
1264 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1267 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1270 if ((old
= entry_read(u
, name
))) {
1271 entry
= entry_copy(old
);
1272 created_new_entry
= FALSE
;
1274 entry
= entry_new();
1276 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1277 pa_assert(sink_input
->volume_writable
);
1279 entry
->channel_map
= sink_input
->channel_map
;
1280 pa_sink_input_get_volume(sink_input
, &entry
->volume
, FALSE
);
1281 entry
->volume_valid
= TRUE
;
1283 volume_updated
= !created_new_entry
1284 && (!old
->volume_valid
1285 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1286 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1289 if (sink_input
->save_muted
) {
1290 entry
->muted
= pa_sink_input_get_mute(sink_input
);
1291 entry
->muted_valid
= TRUE
;
1293 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1296 if (sink_input
->save_sink
) {
1297 pa_xfree(entry
->device
);
1298 entry
->device
= pa_xstrdup(sink_input
->sink
->name
);
1299 entry
->device_valid
= TRUE
;
1301 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1302 if (sink_input
->sink
->card
) {
1303 pa_xfree(entry
->card
);
1304 entry
->card
= pa_xstrdup(sink_input
->sink
->card
->name
);
1305 entry
->card_valid
= TRUE
;
1310 pa_source_output
*source_output
;
1312 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1314 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1317 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1320 if ((old
= entry_read(u
, name
))) {
1321 entry
= entry_copy(old
);
1322 created_new_entry
= FALSE
;
1324 entry
= entry_new();
1326 if (source_output
->save_source
) {
1327 pa_xfree(entry
->device
);
1328 entry
->device
= pa_xstrdup(source_output
->source
->name
);
1329 entry
->device_valid
= TRUE
;
1331 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1333 if (source_output
->source
->card
) {
1334 pa_xfree(entry
->card
);
1335 entry
->card
= pa_xstrdup(source_output
->source
->card
->name
);
1336 entry
->card_valid
= TRUE
;
1345 if (entries_equal(old
, entry
)) {
1355 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1357 if (entry_write(u
, name
, entry
, TRUE
))
1361 if (created_new_entry
) {
1362 de
= dbus_entry_new(u
, name
);
1363 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1364 send_new_entry_signal(de
);
1366 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1369 send_device_updated_signal(de
, entry
);
1371 send_volume_updated_signal(de
, entry
);
1373 send_mute_updated_signal(de
, entry
);
1381 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1386 pa_assert(new_data
);
1388 pa_assert(u
->restore_device
);
1390 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1394 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1395 else if ((e
= entry_read(u
, name
))) {
1398 if (e
->device_valid
)
1399 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1401 if (!s
&& e
->card_valid
) {
1404 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1405 s
= pa_idxset_first(card
->sinks
, NULL
);
1408 /* It might happen that a stream and a sink are set up at the
1409 same time, in which case we want to make sure we don't
1410 interfere with that */
1411 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1412 if (pa_sink_input_new_data_set_sink(new_data
, s
, TRUE
))
1413 pa_log_info("Restoring device for stream %s.", name
);
1423 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1428 pa_assert(new_data
);
1430 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1432 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1435 if ((e
= entry_read(u
, name
))) {
1437 if (u
->restore_volume
&& e
->volume_valid
) {
1438 if (!new_data
->volume_writable
)
1439 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1440 else if (new_data
->volume_is_set
)
1441 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1445 pa_log_info("Restoring volume for sink input %s.", name
);
1448 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1449 pa_sink_input_new_data_set_volume(new_data
, &v
);
1451 new_data
->volume_is_absolute
= FALSE
;
1452 new_data
->save_volume
= TRUE
;
1456 if (u
->restore_muted
&& e
->muted_valid
) {
1458 if (!new_data
->muted_is_set
) {
1459 pa_log_info("Restoring mute state for sink input %s.", name
);
1460 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1461 new_data
->save_muted
= TRUE
;
1463 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1474 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1479 pa_assert(new_data
);
1481 pa_assert(u
->restore_device
);
1483 if (new_data
->direct_on_input
)
1486 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1489 if (new_data
->source
)
1490 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1491 else if ((e
= entry_read(u
, name
))) {
1492 pa_source
*s
= NULL
;
1494 if (e
->device_valid
)
1495 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1497 if (!s
&& e
->card_valid
) {
1500 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1501 s
= pa_idxset_first(card
->sources
, NULL
);
1504 /* It might happen that a stream and a sink are set up at the
1505 same time, in which case we want to make sure we don't
1506 interfere with that */
1507 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1508 pa_log_info("Restoring device for stream %s.", name
);
1509 pa_source_output_new_data_set_source(new_data
, s
, TRUE
);
1520 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1527 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1529 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1533 if (si
->sink
== sink
)
1539 /* Skip this if it is already in the process of being moved
1544 /* It might happen that a stream and a sink are set up at the
1545 same time, in which case we want to make sure we don't
1546 interfere with that */
1547 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1550 if (!(name
= get_name(si
->proplist
, "sink-input")))
1553 if ((e
= entry_read(u
, name
))) {
1554 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1555 pa_sink_input_move_to(si
, sink
, TRUE
);
1566 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1567 pa_source_output
*so
;
1573 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1575 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1579 if (so
->source
== source
)
1582 if (so
->save_source
)
1585 if (so
->direct_on_input
)
1588 /* Skip this if it is already in the process of being moved anyway */
1592 /* It might happen that a stream and a source are set up at the
1593 same time, in which case we want to make sure we don't
1594 interfere with that */
1595 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1598 if (!(name
= get_name(so
->proplist
, "source-output")))
1601 if ((e
= entry_read(u
, name
))) {
1602 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1603 pa_source_output_move_to(so
, source
, TRUE
);
1614 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1621 pa_assert(u
->on_rescue
&& u
->restore_device
);
1623 /* There's no point in doing anything if the core is shut down anyway */
1624 if (c
->state
== PA_CORE_SHUTDOWN
)
1627 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1634 if (!(name
= get_name(si
->proplist
, "sink-input")))
1637 if ((e
= entry_read(u
, name
))) {
1639 if (e
->device_valid
) {
1642 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1644 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1645 pa_sink_input_move_to(si
, d
, TRUE
);
1657 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1658 pa_source_output
*so
;
1664 pa_assert(u
->on_rescue
&& u
->restore_device
);
1666 /* There's no point in doing anything if the core is shut down anyway */
1667 if (c
->state
== PA_CORE_SHUTDOWN
)
1670 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1674 if (so
->direct_on_input
)
1680 if (!(name
= get_name(so
->proplist
, "source-output")))
1683 if ((e
= entry_read(u
, name
))) {
1685 if (e
->device_valid
) {
1688 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1690 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1691 pa_source_output_move_to(so
, d
, TRUE
);
1703 #define EXT_VERSION 1
1705 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
) {
1707 pa_source_output
*so
;
1714 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1718 if (!(n
= get_name(si
->proplist
, "sink-input")))
1721 if (!pa_streq(name
, n
)) {
1727 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1731 pa_log_info("Restoring volume for sink input %s.", name
);
1732 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1733 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1736 if (u
->restore_muted
&& e
->muted_valid
) {
1737 pa_log_info("Restoring mute state for sink input %s.", name
);
1738 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1741 if (u
->restore_device
) {
1742 if (!e
->device_valid
) {
1743 if (si
->save_sink
) {
1744 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1745 /* If the device is not valid we should make sure the
1746 save flag is cleared as the user may have specifically
1747 removed the sink element from the rule. */
1748 si
->save_sink
= FALSE
;
1749 /* This is cheating a bit. The sink input itself has not changed
1750 but the rules governing it's routing have, so we fire this event
1751 such that other routing modules (e.g. module-device-manager)
1752 will pick up the change and reapply their routing */
1753 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1755 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1756 pa_log_info("Restoring device for stream %s.", name
);
1757 pa_sink_input_move_to(si
, s
, TRUE
);
1762 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1766 if (!(n
= get_name(so
->proplist
, "source-output")))
1769 if (!pa_streq(name
, n
)) {
1775 if (u
->restore_device
) {
1776 if (!e
->device_valid
) {
1777 if (so
->save_source
) {
1778 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1779 /* If the device is not valid we should make sure the
1780 save flag is cleared as the user may have specifically
1781 removed the source element from the rule. */
1782 so
->save_source
= FALSE
;
1783 /* This is cheating a bit. The source output itself has not changed
1784 but the rules governing it's routing have, so we fire this event
1785 such that other routing modules (e.g. module-device-manager)
1786 will pick up the change and reapply their routing */
1787 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1789 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1790 pa_log_info("Restoring device for stream %s.", name
);
1791 pa_source_output_move_to(so
, s
, TRUE
);
1798 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1802 done
= !pa_database_first(u
->database
, &key
, NULL
);
1809 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1811 name
= pa_xstrndup(key
.data
, key
.size
);
1812 pa_datum_free(&key
);
1814 if ((e
= entry_read(u
, name
))) {
1816 pa_log("name=%s", name
);
1817 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1818 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1819 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1820 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1831 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1834 pa_tagstruct
*reply
= NULL
;
1843 if (pa_tagstruct_getu32(t
, &command
) < 0)
1846 reply
= pa_tagstruct_new(NULL
, 0);
1847 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1848 pa_tagstruct_putu32(reply
, tag
);
1851 case SUBCOMMAND_TEST
: {
1852 if (!pa_tagstruct_eof(t
))
1855 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1859 case SUBCOMMAND_READ
: {
1863 if (!pa_tagstruct_eof(t
))
1866 done
= !pa_database_first(u
->database
, &key
, NULL
);
1873 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1875 name
= pa_xstrndup(key
.data
, key
.size
);
1876 pa_datum_free(&key
);
1878 if ((e
= entry_read(u
, name
))) {
1882 pa_tagstruct_puts(reply
, name
);
1883 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1884 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1885 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1886 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1899 case SUBCOMMAND_WRITE
: {
1901 pa_bool_t apply_immediately
= FALSE
;
1903 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1904 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1907 if (mode
!= PA_UPDATE_MERGE
&&
1908 mode
!= PA_UPDATE_REPLACE
&&
1909 mode
!= PA_UPDATE_SET
)
1912 if (mode
== PA_UPDATE_SET
) {
1914 struct dbus_entry
*de
;
1917 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
1918 send_entry_removed_signal(de
);
1919 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
1922 pa_database_clear(u
->database
);
1925 while (!pa_tagstruct_eof(t
)) {
1926 const char *name
, *device
;
1928 struct entry
*entry
;
1933 entry
= entry_new();
1935 if (pa_tagstruct_gets(t
, &name
) < 0 ||
1936 pa_tagstruct_get_channel_map(t
, &entry
->channel_map
) ||
1937 pa_tagstruct_get_cvolume(t
, &entry
->volume
) < 0 ||
1938 pa_tagstruct_gets(t
, &device
) < 0 ||
1939 pa_tagstruct_get_boolean(t
, &muted
) < 0)
1942 if (!name
|| !*name
) {
1947 entry
->volume_valid
= entry
->volume
.channels
> 0;
1949 if (entry
->volume_valid
)
1950 if (!pa_cvolume_compatible_with_channel_map(&entry
->volume
, &entry
->channel_map
)) {
1955 entry
->muted
= muted
;
1956 entry
->muted_valid
= TRUE
;
1958 entry
->device
= pa_xstrdup(device
);
1959 entry
->device_valid
= device
&& !!entry
->device
[0];
1961 if (entry
->device_valid
&& !pa_namereg_is_valid_name(entry
->device
)) {
1967 old
= entry_read(u
, name
);
1970 pa_log_debug("Client %s changes entry %s.",
1971 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
1974 if (entry_write(u
, name
, entry
, mode
== PA_UPDATE_REPLACE
)) {
1976 struct dbus_entry
*de
;
1979 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1981 if ((old
->device_valid
!= entry
->device_valid
)
1982 || (entry
->device_valid
&& !pa_streq(entry
->device
, old
->device
)))
1983 send_device_updated_signal(de
, entry
);
1985 if ((old
->volume_valid
!= entry
->volume_valid
)
1986 || (entry
->volume_valid
&& (!pa_cvolume_equal(&entry
->volume
, &old
->volume
)
1987 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
))))
1988 send_volume_updated_signal(de
, entry
);
1990 if (!old
->muted_valid
|| (entry
->muted
!= old
->muted
))
1991 send_mute_updated_signal(de
, entry
);
1994 de
= dbus_entry_new(u
, name
);
1995 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1996 send_new_entry_signal(de
);
2000 if (apply_immediately
)
2001 entry_apply(u
, name
, entry
);
2016 case SUBCOMMAND_DELETE
:
2018 while (!pa_tagstruct_eof(t
)) {
2022 struct dbus_entry
*de
;
2025 if (pa_tagstruct_gets(t
, &name
) < 0)
2029 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
2030 send_entry_removed_signal(de
);
2031 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
2035 key
.data
= (char*) name
;
2036 key
.size
= strlen(name
);
2038 pa_database_unset(u
->database
, &key
);
2045 case SUBCOMMAND_SUBSCRIBE
: {
2049 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
2050 !pa_tagstruct_eof(t
))
2054 pa_idxset_put(u
->subscribed
, c
, NULL
);
2056 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2065 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
2071 pa_tagstruct_free(reply
);
2076 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
2081 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2085 int pa__init(pa_module
*m
) {
2086 pa_modargs
*ma
= NULL
;
2090 pa_source_output
*so
;
2092 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
2100 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2101 pa_log("Failed to parse module arguments");
2105 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2106 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2107 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2108 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2109 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2110 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2114 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2115 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2117 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2120 u
->restore_device
= restore_device
;
2121 u
->restore_volume
= restore_volume
;
2122 u
->restore_muted
= restore_muted
;
2123 u
->on_hotplug
= on_hotplug
;
2124 u
->on_rescue
= on_rescue
;
2125 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2127 u
->protocol
= pa_native_protocol_get(m
->core
);
2128 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2130 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
);
2132 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2134 if (restore_device
) {
2135 /* A little bit earlier than module-intended-roles ... */
2136 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
);
2137 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
);
2140 if (restore_device
&& on_hotplug
) {
2141 /* A little bit earlier than module-intended-roles ... */
2142 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
);
2143 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
);
2146 if (restore_device
&& on_rescue
) {
2147 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2148 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
);
2149 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
);
2152 if (restore_volume
|| restore_muted
)
2153 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
);
2155 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2158 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2159 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2164 pa_log_info("Successfully opened database file '%s'.", fname
);
2168 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2169 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2171 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2172 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2174 /* Create the initial dbus entries. */
2175 done
= !pa_database_first(u
->database
, &key
, NULL
);
2179 struct dbus_entry
*de
;
2182 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2184 name
= pa_xstrndup(key
.data
, key
.size
);
2185 pa_datum_free(&key
);
2187 /* Use entry_read() for checking that the entry is valid. */
2188 if ((e
= entry_read(u
, name
))) {
2189 de
= dbus_entry_new(u
, name
);
2190 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2200 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2201 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2203 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2204 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2206 pa_modargs_free(ma
);
2213 pa_modargs_free(ma
);
2219 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2220 struct dbus_entry
*de
= p
;
2224 dbus_entry_free(de
);
2228 void pa__done(pa_module
*m
) {
2233 if (!(u
= m
->userdata
))
2237 if (u
->dbus_protocol
) {
2238 pa_assert(u
->dbus_entries
);
2240 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2241 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2243 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2245 pa_dbus_protocol_unref(u
->dbus_protocol
);
2249 if (u
->subscription
)
2250 pa_subscription_free(u
->subscription
);
2252 if (u
->sink_input_new_hook_slot
)
2253 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2254 if (u
->sink_input_fixate_hook_slot
)
2255 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2256 if (u
->source_output_new_hook_slot
)
2257 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2259 if (u
->sink_put_hook_slot
)
2260 pa_hook_slot_free(u
->sink_put_hook_slot
);
2261 if (u
->source_put_hook_slot
)
2262 pa_hook_slot_free(u
->source_put_hook_slot
);
2264 if (u
->sink_unlink_hook_slot
)
2265 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2266 if (u
->source_unlink_hook_slot
)
2267 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2269 if (u
->connection_unlink_hook_slot
)
2270 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2272 if (u
->save_time_event
)
2273 u
->core
->mainloop
->time_free(u
->save_time_event
);
2276 pa_database_close(u
->database
);
2279 pa_native_protocol_remove_ext(u
->protocol
, m
);
2280 pa_native_protocol_unref(u
->protocol
);
2284 pa_idxset_free(u
->subscribed
, NULL
, NULL
);