2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
5 Copyright 2009 Tanu Kaskinen
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <sys/types.h>
34 #include <pulse/gccmacro.h>
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/rtclock.h>
40 #include <pulsecore/core-error.h>
41 #include <pulsecore/module.h>
42 #include <pulsecore/core-util.h>
43 #include <pulsecore/modargs.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/core-subscribe.h>
46 #include <pulsecore/sink-input.h>
47 #include <pulsecore/source-output.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/protocol-native.h>
50 #include <pulsecore/pstream.h>
51 #include <pulsecore/pstream-util.h>
52 #include <pulsecore/database.h>
53 #include <pulsecore/tagstruct.h>
56 #include <pulsecore/dbus-util.h>
57 #include <pulsecore/protocol-dbus.h>
60 #include "module-stream-restore-symdef.h"
62 PA_MODULE_AUTHOR("Lennart Poettering");
63 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute/device state of streams");
64 PA_MODULE_VERSION(PACKAGE_VERSION
);
65 PA_MODULE_LOAD_ONCE(TRUE
);
67 "restore_device=<Save/restore sinks/sources?> "
68 "restore_volume=<Save/restore volumes?> "
69 "restore_muted=<Save/restore muted states?> "
70 "on_hotplug=<When new device becomes available, recheck streams?> "
71 "on_rescue=<When device becomes unavailable, recheck streams?>");
73 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
74 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
76 static const char* const valid_modargs
[] = {
88 pa_subscription
*subscription
;
90 *sink_input_new_hook_slot
,
91 *sink_input_fixate_hook_slot
,
92 *source_output_new_hook_slot
,
94 *source_put_hook_slot
,
95 *sink_unlink_hook_slot
,
96 *source_unlink_hook_slot
,
97 *connection_unlink_hook_slot
;
98 pa_time_event
*save_time_event
;
99 pa_database
* database
;
101 pa_bool_t restore_device
:1;
102 pa_bool_t restore_volume
:1;
103 pa_bool_t restore_muted
:1;
104 pa_bool_t on_hotplug
:1;
105 pa_bool_t on_rescue
:1;
107 pa_native_protocol
*protocol
;
108 pa_idxset
*subscribed
;
111 pa_dbus_protocol
*dbus_protocol
;
112 pa_hashmap
*dbus_entries
;
113 uint32_t next_index
; /* For generating object paths for entries. */
117 #define ENTRY_VERSION 1
121 pa_bool_t muted_valid
, volume_valid
, device_valid
, card_valid
;
123 pa_channel_map channel_map
;
134 SUBCOMMAND_SUBSCRIBE
,
139 static struct entry
* entry_new(void);
140 static void entry_free(struct entry
*e
);
141 static struct entry
*entry_read(struct userdata
*u
, const char *name
);
142 static pa_bool_t
entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, pa_bool_t replace
);
143 static struct entry
* entry_copy(const struct entry
*e
);
144 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
);
145 static void trigger_save(struct userdata
*u
);
149 #define OBJECT_PATH "/org/pulseaudio/stream_restore1"
150 #define ENTRY_OBJECT_NAME "entry"
151 #define INTERFACE_STREAM_RESTORE "org.PulseAudio.Ext.StreamRestore1"
152 #define INTERFACE_ENTRY INTERFACE_STREAM_RESTORE ".RestoreEntry"
154 #define DBUS_INTERFACE_REVISION 0
157 struct userdata
*userdata
;
164 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
165 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
167 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
169 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
170 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
172 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
173 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
174 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
175 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
176 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
177 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
178 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
179 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
181 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
183 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
185 enum property_handler_index
{
186 PROPERTY_HANDLER_INTERFACE_REVISION
,
187 PROPERTY_HANDLER_ENTRIES
,
191 enum entry_property_handler_index
{
192 ENTRY_PROPERTY_HANDLER_INDEX
,
193 ENTRY_PROPERTY_HANDLER_NAME
,
194 ENTRY_PROPERTY_HANDLER_DEVICE
,
195 ENTRY_PROPERTY_HANDLER_VOLUME
,
196 ENTRY_PROPERTY_HANDLER_MUTE
,
197 ENTRY_PROPERTY_HANDLER_MAX
200 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
201 [PROPERTY_HANDLER_INTERFACE_REVISION
] = { .property_name
= "InterfaceRevision", .type
= "u", .get_cb
= handle_get_interface_revision
, .set_cb
= NULL
},
202 [PROPERTY_HANDLER_ENTRIES
] = { .property_name
= "Entries", .type
= "ao", .get_cb
= handle_get_entries
, .set_cb
= NULL
}
205 static pa_dbus_property_handler entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MAX
] = {
206 [ENTRY_PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_entry_get_index
, .set_cb
= NULL
},
207 [ENTRY_PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_entry_get_name
, .set_cb
= NULL
},
208 [ENTRY_PROPERTY_HANDLER_DEVICE
] = { .property_name
= "Device", .type
= "s", .get_cb
= handle_entry_get_device
, .set_cb
= handle_entry_set_device
},
209 [ENTRY_PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "a(uu)", .get_cb
= handle_entry_get_volume
, .set_cb
= handle_entry_set_volume
},
210 [ENTRY_PROPERTY_HANDLER_MUTE
] = { .property_name
= "Mute", .type
= "b", .get_cb
= handle_entry_get_mute
, .set_cb
= handle_entry_set_mute
}
213 enum method_handler_index
{
214 METHOD_HANDLER_ADD_ENTRY
,
215 METHOD_HANDLER_GET_ENTRY_BY_NAME
,
219 enum entry_method_handler_index
{
220 ENTRY_METHOD_HANDLER_REMOVE
,
221 ENTRY_METHOD_HANDLER_MAX
224 static pa_dbus_arg_info add_entry_args
[] = { { "name", "s", "in" },
225 { "device", "s", "in" },
226 { "volume", "a(uu)", "in" },
227 { "mute", "b", "in" },
228 { "entry", "o", "out" } };
229 static pa_dbus_arg_info get_entry_by_name_args
[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
231 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
232 [METHOD_HANDLER_ADD_ENTRY
] = {
233 .method_name
= "AddEntry",
234 .arguments
= add_entry_args
,
235 .n_arguments
= sizeof(add_entry_args
) / sizeof(pa_dbus_arg_info
),
236 .receive_cb
= handle_add_entry
},
237 [METHOD_HANDLER_GET_ENTRY_BY_NAME
] = {
238 .method_name
= "GetEntryByName",
239 .arguments
= get_entry_by_name_args
,
240 .n_arguments
= sizeof(get_entry_by_name_args
) / sizeof(pa_dbus_arg_info
),
241 .receive_cb
= handle_get_entry_by_name
}
244 static pa_dbus_method_handler entry_method_handlers
[ENTRY_METHOD_HANDLER_MAX
] = {
245 [ENTRY_METHOD_HANDLER_REMOVE
] = {
246 .method_name
= "Remove",
249 .receive_cb
= handle_entry_remove
}
254 SIGNAL_ENTRY_REMOVED
,
258 enum entry_signal_index
{
259 ENTRY_SIGNAL_DEVICE_UPDATED
,
260 ENTRY_SIGNAL_VOLUME_UPDATED
,
261 ENTRY_SIGNAL_MUTE_UPDATED
,
265 static pa_dbus_arg_info new_entry_args
[] = { { "entry", "o", NULL
} };
266 static pa_dbus_arg_info entry_removed_args
[] = { { "entry", "o", NULL
} };
268 static pa_dbus_arg_info entry_device_updated_args
[] = { { "device", "s", NULL
} };
269 static pa_dbus_arg_info entry_volume_updated_args
[] = { { "volume", "a(uu)", NULL
} };
270 static pa_dbus_arg_info entry_mute_updated_args
[] = { { "muted", "b", NULL
} };
272 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
273 [SIGNAL_NEW_ENTRY
] = { .name
= "NewEntry", .arguments
= new_entry_args
, .n_arguments
= 1 },
274 [SIGNAL_ENTRY_REMOVED
] = { .name
= "EntryRemoved", .arguments
= entry_removed_args
, .n_arguments
= 1 }
277 static pa_dbus_signal_info entry_signals
[ENTRY_SIGNAL_MAX
] = {
278 [ENTRY_SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= entry_device_updated_args
, .n_arguments
= 1 },
279 [ENTRY_SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= entry_volume_updated_args
, .n_arguments
= 1 },
280 [ENTRY_SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= entry_mute_updated_args
, .n_arguments
= 1 }
283 static pa_dbus_interface_info stream_restore_interface_info
= {
284 .name
= INTERFACE_STREAM_RESTORE
,
285 .method_handlers
= method_handlers
,
286 .n_method_handlers
= METHOD_HANDLER_MAX
,
287 .property_handlers
= property_handlers
,
288 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
289 .get_all_properties_cb
= handle_get_all
,
291 .n_signals
= SIGNAL_MAX
294 static pa_dbus_interface_info entry_interface_info
= {
295 .name
= INTERFACE_ENTRY
,
296 .method_handlers
= entry_method_handlers
,
297 .n_method_handlers
= ENTRY_METHOD_HANDLER_MAX
,
298 .property_handlers
= entry_property_handlers
,
299 .n_property_handlers
= ENTRY_PROPERTY_HANDLER_MAX
,
300 .get_all_properties_cb
= handle_entry_get_all
,
301 .signals
= entry_signals
,
302 .n_signals
= ENTRY_SIGNAL_MAX
305 static struct dbus_entry
*dbus_entry_new(struct userdata
*u
, const char *entry_name
) {
306 struct dbus_entry
*de
;
309 pa_assert(entry_name
);
310 pa_assert(*entry_name
);
312 de
= pa_xnew(struct dbus_entry
, 1);
314 de
->entry_name
= pa_xstrdup(entry_name
);
315 de
->index
= u
->next_index
++;
316 de
->object_path
= pa_sprintf_malloc("%s/%s%u", OBJECT_PATH
, ENTRY_OBJECT_NAME
, de
->index
);
318 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, de
->object_path
, &entry_interface_info
, de
) >= 0);
323 static void dbus_entry_free(struct dbus_entry
*de
) {
326 pa_assert_se(pa_dbus_protocol_remove_interface(de
->userdata
->dbus_protocol
, de
->object_path
, entry_interface_info
.name
) >= 0);
328 pa_xfree(de
->entry_name
);
329 pa_xfree(de
->object_path
);
332 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
333 * are a channel position and a volume value, respectively. The result is
334 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
335 * element. If the data is invalid, an error reply is sent and a negative
336 * number is returned. In case of a failure we make no guarantees about the
337 * state of map and vol. In case of an empty array the channels field of both
338 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
339 * before returning. */
340 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
341 DBusMessageIter array_iter
;
342 DBusMessageIter struct_iter
;
347 pa_assert(pa_streq(dbus_message_iter_get_signature(iter
), "a(uu)"));
351 pa_channel_map_init(map
);
352 pa_cvolume_init(vol
);
357 dbus_message_iter_recurse(iter
, &array_iter
);
359 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
360 dbus_uint32_t chan_pos
;
361 dbus_uint32_t chan_vol
;
363 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
365 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
367 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
368 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
372 pa_assert_se(dbus_message_iter_next(&struct_iter
));
373 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
375 if (!PA_VOLUME_IS_VALID(chan_vol
)) {
376 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
380 if (map
->channels
< PA_CHANNELS_MAX
) {
381 map
->map
[map
->channels
] = chan_pos
;
382 vol
->values
[map
->channels
] = chan_vol
;
387 dbus_message_iter_next(&array_iter
);
390 if (map
->channels
> PA_CHANNELS_MAX
) {
391 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
395 dbus_message_iter_next(iter
);
400 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
401 DBusMessageIter array_iter
;
402 DBusMessageIter struct_iter
;
408 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
410 if (!e
->volume_valid
) {
411 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
415 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
416 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
418 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
419 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
421 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
424 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
427 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
428 DBusMessageIter variant_iter
;
433 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
435 append_volume(&variant_iter
, e
);
437 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
440 static void send_new_entry_signal(struct dbus_entry
*entry
) {
441 DBusMessage
*signal_msg
;
445 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
446 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
447 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
448 dbus_message_unref(signal_msg
);
451 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
452 DBusMessage
*signal_msg
;
456 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
457 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
458 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
459 dbus_message_unref(signal_msg
);
462 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
463 DBusMessage
*signal_msg
;
469 device
= e
->device_valid
? e
->device
: "";
471 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
472 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
473 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
474 dbus_message_unref(signal_msg
);
477 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
478 DBusMessage
*signal_msg
;
479 DBusMessageIter msg_iter
;
484 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
485 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
486 append_volume(&msg_iter
, e
);
487 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
488 dbus_message_unref(signal_msg
);
491 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
492 DBusMessage
*signal_msg
;
498 pa_assert(e
->muted_valid
);
502 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
503 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
504 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
505 dbus_message_unref(signal_msg
);
508 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
509 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
514 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
517 /* The caller frees the array, but not the strings. */
518 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
519 const char **entries
;
522 struct dbus_entry
*de
;
527 *n
= pa_hashmap_size(u
->dbus_entries
);
532 entries
= pa_xnew(const char *, *n
);
534 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
)
535 entries
[i
++] = de
->object_path
;
540 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
541 struct userdata
*u
= userdata
;
542 const char **entries
;
549 entries
= get_entries(u
, &n
);
551 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
556 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
557 struct userdata
*u
= userdata
;
558 DBusMessage
*reply
= NULL
;
559 DBusMessageIter msg_iter
;
560 DBusMessageIter dict_iter
;
561 dbus_uint32_t interface_revision
;
562 const char **entries
;
569 interface_revision
= DBUS_INTERFACE_REVISION
;
570 entries
= get_entries(u
, &n_entries
);
572 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
574 dbus_message_iter_init_append(reply
, &msg_iter
);
575 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
577 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
578 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
580 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
582 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
584 dbus_message_unref(reply
);
589 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
590 struct userdata
*u
= userdata
;
591 DBusMessageIter msg_iter
;
592 const char *name
= NULL
;
593 const char *device
= NULL
;
596 dbus_bool_t muted
= FALSE
;
597 dbus_bool_t apply_immediately
= FALSE
;
598 struct dbus_entry
*dbus_entry
= NULL
;
599 struct entry
*e
= NULL
;
605 pa_assert_se(dbus_message_iter_init(msg
, &msg_iter
));
606 dbus_message_iter_get_basic(&msg_iter
, &name
);
608 pa_assert_se(dbus_message_iter_next(&msg_iter
));
609 dbus_message_iter_get_basic(&msg_iter
, &device
);
611 pa_assert_se(dbus_message_iter_next(&msg_iter
));
612 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
615 dbus_message_iter_get_basic(&msg_iter
, &muted
);
617 pa_assert_se(dbus_message_iter_next(&msg_iter
));
618 dbus_message_iter_get_basic(&msg_iter
, &apply_immediately
);
621 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
625 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
626 pa_bool_t mute_updated
= FALSE
;
627 pa_bool_t volume_updated
= FALSE
;
628 pa_bool_t device_updated
= FALSE
;
630 pa_assert_se(e
= entry_read(u
, name
));
631 mute_updated
= e
->muted
!= muted
;
633 e
->muted_valid
= TRUE
;
635 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
637 e
->channel_map
= map
;
638 e
->volume_valid
= !!map
.channels
;
640 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
642 e
->device
= pa_xstrdup(device
);
643 e
->device_valid
= !!device
[0];
646 send_mute_updated_signal(dbus_entry
, e
);
648 send_volume_updated_signal(dbus_entry
, e
);
650 send_device_updated_signal(dbus_entry
, e
);
653 dbus_entry
= dbus_entry_new(u
, name
);
654 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) == 0);
657 e
->muted_valid
= TRUE
;
658 e
->volume_valid
= !!map
.channels
;
659 e
->device_valid
= !!device
[0];
662 e
->channel_map
= map
;
663 e
->device
= pa_xstrdup(device
);
665 send_new_entry_signal(dbus_entry
);
668 pa_assert_se(entry_write(u
, name
, e
, TRUE
));
670 if (apply_immediately
)
671 entry_apply(u
, name
, e
);
675 pa_dbus_send_empty_reply(conn
, msg
);
680 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
681 struct userdata
*u
= userdata
;
683 struct dbus_entry
*de
;
689 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
));
691 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
692 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
696 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
699 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
700 struct dbus_entry
*de
= userdata
;
706 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
709 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
710 struct dbus_entry
*de
= userdata
;
716 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
719 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
720 struct dbus_entry
*de
= userdata
;
728 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
730 device
= e
->device_valid
? e
->device
: "";
732 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
737 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
738 struct dbus_entry
*de
= userdata
;
748 dbus_message_iter_get_basic(iter
, &device
);
750 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
752 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
756 e
->device
= pa_xstrdup(device
);
757 e
->device_valid
= !!device
[0];
759 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
761 entry_apply(de
->userdata
, de
->entry_name
, e
);
762 send_device_updated_signal(de
, e
);
763 trigger_save(de
->userdata
);
766 pa_dbus_send_empty_reply(conn
, msg
);
771 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
772 struct dbus_entry
*de
= userdata
;
774 DBusMessageIter msg_iter
;
781 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
783 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
785 dbus_message_iter_init_append(reply
, &msg_iter
);
786 append_volume_variant(&msg_iter
, e
);
788 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
793 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
794 struct dbus_entry
*de
= userdata
;
797 struct entry
*e
= NULL
;
798 pa_bool_t updated
= FALSE
;
805 if (get_volume_arg(conn
, msg
, iter
, &map
, &vol
) < 0)
808 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
810 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
814 e
->channel_map
= map
;
815 e
->volume_valid
= !!map
.channels
;
817 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
819 entry_apply(de
->userdata
, de
->entry_name
, e
);
820 send_volume_updated_signal(de
, e
);
821 trigger_save(de
->userdata
);
824 pa_dbus_send_empty_reply(conn
, msg
);
829 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
830 struct dbus_entry
*de
= userdata
;
838 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
840 mute
= e
->muted_valid
? e
->muted
: FALSE
;
842 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &mute
);
847 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
848 struct dbus_entry
*de
= userdata
;
858 dbus_message_iter_get_basic(iter
, &mute
);
860 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
862 updated
= !e
->muted_valid
|| e
->muted
!= mute
;
866 e
->muted_valid
= TRUE
;
868 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
870 entry_apply(de
->userdata
, de
->entry_name
, e
);
871 send_mute_updated_signal(de
, e
);
872 trigger_save(de
->userdata
);
875 pa_dbus_send_empty_reply(conn
, msg
);
880 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
881 struct dbus_entry
*de
= userdata
;
883 DBusMessage
*reply
= NULL
;
884 DBusMessageIter msg_iter
;
885 DBusMessageIter dict_iter
;
886 DBusMessageIter dict_entry_iter
;
894 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
896 device
= e
->device_valid
? e
->device
: "";
897 mute
= e
->muted_valid
? e
->muted
: FALSE
;
899 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
901 dbus_message_iter_init_append(reply
, &msg_iter
);
902 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
904 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
905 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
906 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
908 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
910 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
911 append_volume_variant(&dict_entry_iter
, e
);
913 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
915 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &mute
);
917 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
919 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
921 dbus_message_unref(reply
);
926 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
927 struct dbus_entry
*de
= userdata
;
934 key
.data
= de
->entry_name
;
935 key
.size
= strlen(de
->entry_name
);
937 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
939 send_entry_removed_signal(de
);
940 trigger_save(de
->userdata
);
942 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
945 pa_dbus_send_empty_reply(conn
, msg
);
948 #endif /* HAVE_DBUS */
950 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
951 struct userdata
*u
= userdata
;
957 pa_assert(e
== u
->save_time_event
);
958 u
->core
->mainloop
->time_free(u
->save_time_event
);
959 u
->save_time_event
= NULL
;
961 pa_database_sync(u
->database
);
962 pa_log_info("Synced.");
965 static char *get_name(pa_proplist
*p
, const char *prefix
) {
972 if ((r
= pa_proplist_gets(p
, IDENTIFICATION_PROPERTY
)))
973 return pa_xstrdup(r
);
975 if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_ROLE
)))
976 t
= pa_sprintf_malloc("%s-by-media-role:%s", prefix
, r
);
977 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_ID
)))
978 t
= pa_sprintf_malloc("%s-by-application-id:%s", prefix
, r
);
979 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_NAME
)))
980 t
= pa_sprintf_malloc("%s-by-application-name:%s", prefix
, r
);
981 else if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
)))
982 t
= pa_sprintf_malloc("%s-by-media-name:%s", prefix
, r
);
984 t
= pa_sprintf_malloc("%s-fallback:%s", prefix
, r
);
986 pa_proplist_sets(p
, IDENTIFICATION_PROPERTY
, t
);
990 static struct entry
* entry_new(void) {
991 struct entry
*r
= pa_xnew0(struct entry
, 1);
992 r
->version
= ENTRY_VERSION
;
996 static void entry_free(struct entry
* e
) {
1004 static pa_bool_t
entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, pa_bool_t replace
) {
1013 t
= pa_tagstruct_new(NULL
, 0);
1014 pa_tagstruct_putu8(t
, e
->version
);
1015 pa_tagstruct_put_boolean(t
, e
->volume_valid
);
1016 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
1017 pa_tagstruct_put_cvolume(t
, &e
->volume
);
1018 pa_tagstruct_put_boolean(t
, e
->muted_valid
);
1019 pa_tagstruct_put_boolean(t
, e
->muted
);
1020 pa_tagstruct_put_boolean(t
, e
->device_valid
);
1021 pa_tagstruct_puts(t
, e
->device
);
1022 pa_tagstruct_put_boolean(t
, e
->card_valid
);
1023 pa_tagstruct_puts(t
, e
->card
);
1025 key
.data
= (char *) name
;
1026 key
.size
= strlen(name
);
1028 data
.data
= (void*)pa_tagstruct_data(t
, &data
.size
);
1030 r
= (pa_database_set(u
->database
, &key
, &data
, replace
) == 0);
1032 pa_tagstruct_free(t
);
1037 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1039 #define LEGACY_ENTRY_VERSION 3
1040 static struct entry
* legacy_entry_read(struct userdata
*u
, pa_datum
*data
) {
1041 struct legacy_entry
{
1043 pa_bool_t muted_valid
:1, volume_valid
:1, device_valid
:1, card_valid
:1;
1045 pa_channel_map channel_map
;
1047 char device
[PA_NAME_MAX
];
1048 char card
[PA_NAME_MAX
];
1050 struct legacy_entry
*le
;
1056 if (data
->size
!= sizeof(struct legacy_entry
)) {
1057 pa_log_debug("Size does not match.");
1061 le
= (struct legacy_entry
*)data
->data
;
1063 if (le
->version
!= LEGACY_ENTRY_VERSION
) {
1064 pa_log_debug("Version mismatch.");
1068 if (!memchr(le
->device
, 0, sizeof(le
->device
))) {
1069 pa_log_warn("Device has missing NUL byte.");
1073 if (!memchr(le
->card
, 0, sizeof(le
->card
))) {
1074 pa_log_warn("Card has missing NUL byte.");
1079 e
->card
= pa_xstrdup(le
->card
);
1084 static struct entry
*entry_read(struct userdata
*u
, const char *name
) {
1086 struct entry
*e
= NULL
;
1087 pa_tagstruct
*t
= NULL
;
1088 const char *device
, *card
;
1093 key
.data
= (char*) name
;
1094 key
.size
= strlen(name
);
1098 if (!pa_database_get(u
->database
, &key
, &data
))
1101 t
= pa_tagstruct_new(data
.data
, data
.size
);
1104 if (pa_tagstruct_getu8(t
, &e
->version
) < 0 ||
1105 e
->version
> ENTRY_VERSION
||
1106 pa_tagstruct_get_boolean(t
, &e
->volume_valid
) < 0 ||
1107 pa_tagstruct_get_channel_map(t
, &e
->channel_map
) < 0 ||
1108 pa_tagstruct_get_cvolume(t
, &e
->volume
) < 0 ||
1109 pa_tagstruct_get_boolean(t
, &e
->muted_valid
) < 0 ||
1110 pa_tagstruct_get_boolean(t
, &e
->muted
) < 0 ||
1111 pa_tagstruct_get_boolean(t
, &e
->device_valid
) < 0 ||
1112 pa_tagstruct_gets(t
, &device
) < 0 ||
1113 pa_tagstruct_get_boolean(t
, &e
->card_valid
) < 0 ||
1114 pa_tagstruct_gets(t
, &card
) < 0) {
1119 e
->device
= pa_xstrdup(device
);
1120 e
->card
= pa_xstrdup(card
);
1122 if (!pa_tagstruct_eof(t
))
1125 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1126 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1130 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1131 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1135 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1136 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1140 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1141 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1145 pa_tagstruct_free(t
);
1146 pa_datum_free(&data
);
1152 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name
);
1157 pa_tagstruct_free(t
);
1159 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1160 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name
);
1161 if ((e
= legacy_entry_read(u
, &data
))) {
1162 pa_log_debug("Success. Saving new format for key: %s", name
);
1163 if (entry_write(u
, name
, e
, TRUE
))
1165 pa_datum_free(&data
);
1168 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name
);
1171 pa_datum_free(&data
);
1175 static struct entry
* entry_copy(const struct entry
*e
) {
1181 r
->device
= pa_xstrdup(e
->device
);
1182 r
->card
= pa_xstrdup(e
->card
);
1186 static void trigger_save(struct userdata
*u
) {
1187 pa_native_connection
*c
;
1190 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1193 t
= pa_tagstruct_new(NULL
, 0);
1194 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1195 pa_tagstruct_putu32(t
, 0);
1196 pa_tagstruct_putu32(t
, u
->module
->index
);
1197 pa_tagstruct_puts(t
, u
->module
->name
);
1198 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1200 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1203 if (u
->save_time_event
)
1206 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1209 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1215 if (a
->device_valid
!= b
->device_valid
||
1216 (a
->device_valid
&& !pa_streq(a
->device
, b
->device
)))
1219 if (a
->card_valid
!= b
->card_valid
||
1220 (a
->card_valid
&& !pa_streq(a
->card
, b
->card
)))
1223 if (a
->muted_valid
!= b
->muted_valid
||
1224 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1228 if (a
->volume_valid
!= b
->volume_valid
||
1229 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1235 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1236 struct userdata
*u
= userdata
;
1237 struct entry
*entry
, *old
= NULL
;
1240 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1241 * clutter these are defined here unconditionally. */
1242 pa_bool_t created_new_entry
= TRUE
;
1243 pa_bool_t device_updated
= FALSE
;
1244 pa_bool_t volume_updated
= FALSE
;
1245 pa_bool_t mute_updated
= FALSE
;
1248 struct dbus_entry
*de
= NULL
;
1254 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1255 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1256 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1257 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1260 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1261 pa_sink_input
*sink_input
;
1263 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1266 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1269 if ((old
= entry_read(u
, name
))) {
1270 entry
= entry_copy(old
);
1271 created_new_entry
= FALSE
;
1273 entry
= entry_new();
1275 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1276 pa_assert(sink_input
->volume_writable
);
1278 entry
->channel_map
= sink_input
->channel_map
;
1279 pa_sink_input_get_volume(sink_input
, &entry
->volume
, FALSE
);
1280 entry
->volume_valid
= TRUE
;
1282 volume_updated
= !created_new_entry
1283 && (!old
->volume_valid
1284 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1285 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1288 if (sink_input
->save_muted
) {
1289 entry
->muted
= pa_sink_input_get_mute(sink_input
);
1290 entry
->muted_valid
= TRUE
;
1292 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1295 if (sink_input
->save_sink
) {
1296 pa_xfree(entry
->device
);
1297 entry
->device
= pa_xstrdup(sink_input
->sink
->name
);
1298 entry
->device_valid
= TRUE
;
1300 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1301 if (sink_input
->sink
->card
) {
1302 pa_xfree(entry
->card
);
1303 entry
->card
= pa_xstrdup(sink_input
->sink
->card
->name
);
1304 entry
->card_valid
= TRUE
;
1309 pa_source_output
*source_output
;
1311 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1313 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1316 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1319 if ((old
= entry_read(u
, name
))) {
1320 entry
= entry_copy(old
);
1321 created_new_entry
= FALSE
;
1323 entry
= entry_new();
1325 if (source_output
->save_source
) {
1326 pa_xfree(entry
->device
);
1327 entry
->device
= pa_xstrdup(source_output
->source
->name
);
1328 entry
->device_valid
= TRUE
;
1330 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1332 if (source_output
->source
->card
) {
1333 pa_xfree(entry
->card
);
1334 entry
->card
= pa_xstrdup(source_output
->source
->card
->name
);
1335 entry
->card_valid
= TRUE
;
1344 if (entries_equal(old
, entry
)) {
1354 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1356 if (entry_write(u
, name
, entry
, TRUE
))
1360 if (created_new_entry
) {
1361 de
= dbus_entry_new(u
, name
);
1362 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1363 send_new_entry_signal(de
);
1365 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1368 send_device_updated_signal(de
, entry
);
1370 send_volume_updated_signal(de
, entry
);
1372 send_mute_updated_signal(de
, entry
);
1380 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1385 pa_assert(new_data
);
1387 pa_assert(u
->restore_device
);
1389 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1393 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1394 else if ((e
= entry_read(u
, name
))) {
1397 if (e
->device_valid
)
1398 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1400 if (!s
&& e
->card_valid
) {
1403 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1404 s
= pa_idxset_first(card
->sinks
, NULL
);
1407 /* It might happen that a stream and a sink are set up at the
1408 same time, in which case we want to make sure we don't
1409 interfere with that */
1410 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1411 if (pa_sink_input_new_data_set_sink(new_data
, s
, TRUE
))
1412 pa_log_info("Restoring device for stream %s.", name
);
1422 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1427 pa_assert(new_data
);
1429 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1431 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1434 if ((e
= entry_read(u
, name
))) {
1436 if (u
->restore_volume
&& e
->volume_valid
) {
1437 if (!new_data
->volume_writable
)
1438 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1439 else if (new_data
->volume_is_set
)
1440 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1444 pa_log_info("Restoring volume for sink input %s.", name
);
1447 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1448 pa_sink_input_new_data_set_volume(new_data
, &v
);
1450 new_data
->volume_is_absolute
= FALSE
;
1451 new_data
->save_volume
= TRUE
;
1455 if (u
->restore_muted
&& e
->muted_valid
) {
1457 if (!new_data
->muted_is_set
) {
1458 pa_log_info("Restoring mute state for sink input %s.", name
);
1459 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1460 new_data
->save_muted
= TRUE
;
1462 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1473 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1478 pa_assert(new_data
);
1480 pa_assert(u
->restore_device
);
1482 if (new_data
->direct_on_input
)
1485 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1488 if (new_data
->source
)
1489 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1490 else if ((e
= entry_read(u
, name
))) {
1491 pa_source
*s
= NULL
;
1493 if (e
->device_valid
)
1494 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1496 if (!s
&& e
->card_valid
) {
1499 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1500 s
= pa_idxset_first(card
->sources
, NULL
);
1503 /* It might happen that a stream and a sink are set up at the
1504 same time, in which case we want to make sure we don't
1505 interfere with that */
1506 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1507 pa_log_info("Restoring device for stream %s.", name
);
1508 pa_source_output_new_data_set_source(new_data
, s
, TRUE
);
1519 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1526 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1528 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1532 if (si
->sink
== sink
)
1538 /* Skip this if it is already in the process of being moved
1543 /* It might happen that a stream and a sink are set up at the
1544 same time, in which case we want to make sure we don't
1545 interfere with that */
1546 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1549 if (!(name
= get_name(si
->proplist
, "sink-input")))
1552 if ((e
= entry_read(u
, name
))) {
1553 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1554 pa_sink_input_move_to(si
, sink
, TRUE
);
1565 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1566 pa_source_output
*so
;
1572 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1574 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1578 if (so
->source
== source
)
1581 if (so
->save_source
)
1584 if (so
->direct_on_input
)
1587 /* Skip this if it is already in the process of being moved anyway */
1591 /* It might happen that a stream and a source are set up at the
1592 same time, in which case we want to make sure we don't
1593 interfere with that */
1594 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1597 if (!(name
= get_name(so
->proplist
, "source-output")))
1600 if ((e
= entry_read(u
, name
))) {
1601 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1602 pa_source_output_move_to(so
, source
, TRUE
);
1613 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1620 pa_assert(u
->on_rescue
&& u
->restore_device
);
1622 /* There's no point in doing anything if the core is shut down anyway */
1623 if (c
->state
== PA_CORE_SHUTDOWN
)
1626 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1633 if (!(name
= get_name(si
->proplist
, "sink-input")))
1636 if ((e
= entry_read(u
, name
))) {
1638 if (e
->device_valid
) {
1641 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1643 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1644 pa_sink_input_move_to(si
, d
, TRUE
);
1656 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1657 pa_source_output
*so
;
1663 pa_assert(u
->on_rescue
&& u
->restore_device
);
1665 /* There's no point in doing anything if the core is shut down anyway */
1666 if (c
->state
== PA_CORE_SHUTDOWN
)
1669 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1673 if (so
->direct_on_input
)
1679 if (!(name
= get_name(so
->proplist
, "source-output")))
1682 if ((e
= entry_read(u
, name
))) {
1684 if (e
->device_valid
) {
1687 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1689 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1690 pa_source_output_move_to(so
, d
, TRUE
);
1702 #define EXT_VERSION 1
1704 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
) {
1706 pa_source_output
*so
;
1713 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1717 if (!(n
= get_name(si
->proplist
, "sink-input")))
1720 if (!pa_streq(name
, n
)) {
1726 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1730 pa_log_info("Restoring volume for sink input %s.", name
);
1731 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1732 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1735 if (u
->restore_muted
&& e
->muted_valid
) {
1736 pa_log_info("Restoring mute state for sink input %s.", name
);
1737 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1740 if (u
->restore_device
) {
1741 if (!e
->device_valid
) {
1742 if (si
->save_sink
) {
1743 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1744 /* If the device is not valid we should make sure the
1745 save flag is cleared as the user may have specifically
1746 removed the sink element from the rule. */
1747 si
->save_sink
= FALSE
;
1748 /* This is cheating a bit. The sink input itself has not changed
1749 but the rules governing it's routing have, so we fire this event
1750 such that other routing modules (e.g. module-device-manager)
1751 will pick up the change and reapply their routing */
1752 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1754 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1755 pa_log_info("Restoring device for stream %s.", name
);
1756 pa_sink_input_move_to(si
, s
, TRUE
);
1761 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1765 if (!(n
= get_name(so
->proplist
, "source-output")))
1768 if (!pa_streq(name
, n
)) {
1774 if (u
->restore_device
) {
1775 if (!e
->device_valid
) {
1776 if (so
->save_source
) {
1777 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1778 /* If the device is not valid we should make sure the
1779 save flag is cleared as the user may have specifically
1780 removed the source element from the rule. */
1781 so
->save_source
= FALSE
;
1782 /* This is cheating a bit. The source output itself has not changed
1783 but the rules governing it's routing have, so we fire this event
1784 such that other routing modules (e.g. module-device-manager)
1785 will pick up the change and reapply their routing */
1786 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1788 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1789 pa_log_info("Restoring device for stream %s.", name
);
1790 pa_source_output_move_to(so
, s
, TRUE
);
1797 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1801 done
= !pa_database_first(u
->database
, &key
, NULL
);
1808 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1810 name
= pa_xstrndup(key
.data
, key
.size
);
1811 pa_datum_free(&key
);
1813 if ((e
= entry_read(u
, name
))) {
1815 pa_log("name=%s", name
);
1816 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1817 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1818 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1819 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1830 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1833 pa_tagstruct
*reply
= NULL
;
1842 if (pa_tagstruct_getu32(t
, &command
) < 0)
1845 reply
= pa_tagstruct_new(NULL
, 0);
1846 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1847 pa_tagstruct_putu32(reply
, tag
);
1850 case SUBCOMMAND_TEST
: {
1851 if (!pa_tagstruct_eof(t
))
1854 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1858 case SUBCOMMAND_READ
: {
1862 if (!pa_tagstruct_eof(t
))
1865 done
= !pa_database_first(u
->database
, &key
, NULL
);
1872 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1874 name
= pa_xstrndup(key
.data
, key
.size
);
1875 pa_datum_free(&key
);
1877 if ((e
= entry_read(u
, name
))) {
1881 pa_tagstruct_puts(reply
, name
);
1882 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1883 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1884 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1885 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1898 case SUBCOMMAND_WRITE
: {
1900 pa_bool_t apply_immediately
= FALSE
;
1902 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1903 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1906 if (mode
!= PA_UPDATE_MERGE
&&
1907 mode
!= PA_UPDATE_REPLACE
&&
1908 mode
!= PA_UPDATE_SET
)
1911 if (mode
== PA_UPDATE_SET
) {
1913 struct dbus_entry
*de
;
1916 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
1917 send_entry_removed_signal(de
);
1918 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
1921 pa_database_clear(u
->database
);
1924 while (!pa_tagstruct_eof(t
)) {
1925 const char *name
, *device
;
1927 struct entry
*entry
;
1932 entry
= entry_new();
1934 if (pa_tagstruct_gets(t
, &name
) < 0 ||
1935 pa_tagstruct_get_channel_map(t
, &entry
->channel_map
) ||
1936 pa_tagstruct_get_cvolume(t
, &entry
->volume
) < 0 ||
1937 pa_tagstruct_gets(t
, &device
) < 0 ||
1938 pa_tagstruct_get_boolean(t
, &muted
) < 0)
1941 if (!name
|| !*name
) {
1946 entry
->volume_valid
= entry
->volume
.channels
> 0;
1948 if (entry
->volume_valid
)
1949 if (!pa_cvolume_compatible_with_channel_map(&entry
->volume
, &entry
->channel_map
)) {
1954 entry
->muted
= muted
;
1955 entry
->muted_valid
= TRUE
;
1957 entry
->device
= pa_xstrdup(device
);
1958 entry
->device_valid
= device
&& !!entry
->device
[0];
1960 if (entry
->device_valid
&& !pa_namereg_is_valid_name(entry
->device
)) {
1966 old
= entry_read(u
, name
);
1969 pa_log_debug("Client %s changes entry %s.",
1970 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
1973 if (entry_write(u
, name
, entry
, mode
== PA_UPDATE_REPLACE
)) {
1975 struct dbus_entry
*de
;
1978 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1980 if ((old
->device_valid
!= entry
->device_valid
)
1981 || (entry
->device_valid
&& !pa_streq(entry
->device
, old
->device
)))
1982 send_device_updated_signal(de
, entry
);
1984 if ((old
->volume_valid
!= entry
->volume_valid
)
1985 || (entry
->volume_valid
&& (!pa_cvolume_equal(&entry
->volume
, &old
->volume
)
1986 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
))))
1987 send_volume_updated_signal(de
, entry
);
1989 if (!old
->muted_valid
|| (entry
->muted
!= old
->muted
))
1990 send_mute_updated_signal(de
, entry
);
1993 de
= dbus_entry_new(u
, name
);
1994 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1995 send_new_entry_signal(de
);
1999 if (apply_immediately
)
2000 entry_apply(u
, name
, entry
);
2015 case SUBCOMMAND_DELETE
:
2017 while (!pa_tagstruct_eof(t
)) {
2021 struct dbus_entry
*de
;
2024 if (pa_tagstruct_gets(t
, &name
) < 0)
2028 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
2029 send_entry_removed_signal(de
);
2030 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
2034 key
.data
= (char*) name
;
2035 key
.size
= strlen(name
);
2037 pa_database_unset(u
->database
, &key
);
2044 case SUBCOMMAND_SUBSCRIBE
: {
2048 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
2049 !pa_tagstruct_eof(t
))
2053 pa_idxset_put(u
->subscribed
, c
, NULL
);
2055 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2064 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
2070 pa_tagstruct_free(reply
);
2075 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
2080 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2084 int pa__init(pa_module
*m
) {
2085 pa_modargs
*ma
= NULL
;
2089 pa_source_output
*so
;
2091 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
2099 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2100 pa_log("Failed to parse module arguments");
2104 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2105 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2106 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2107 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2108 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2109 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2113 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2114 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2116 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2119 u
->restore_device
= restore_device
;
2120 u
->restore_volume
= restore_volume
;
2121 u
->restore_muted
= restore_muted
;
2122 u
->on_hotplug
= on_hotplug
;
2123 u
->on_rescue
= on_rescue
;
2124 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2126 u
->protocol
= pa_native_protocol_get(m
->core
);
2127 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2129 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
);
2131 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2133 if (restore_device
) {
2134 /* A little bit earlier than module-intended-roles ... */
2135 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
);
2136 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
);
2139 if (restore_device
&& on_hotplug
) {
2140 /* A little bit earlier than module-intended-roles ... */
2141 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
);
2142 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
);
2145 if (restore_device
&& on_rescue
) {
2146 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2147 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
);
2148 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
);
2151 if (restore_volume
|| restore_muted
)
2152 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
);
2154 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2157 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2158 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2163 pa_log_info("Successfully opened database file '%s'.", fname
);
2167 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2168 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2170 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2171 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2173 /* Create the initial dbus entries. */
2174 done
= !pa_database_first(u
->database
, &key
, NULL
);
2178 struct dbus_entry
*de
;
2181 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2183 name
= pa_xstrndup(key
.data
, key
.size
);
2184 pa_datum_free(&key
);
2186 /* Use entry_read() for checking that the entry is valid. */
2187 if ((e
= entry_read(u
, name
))) {
2188 de
= dbus_entry_new(u
, name
);
2189 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2199 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2200 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2202 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2203 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2205 pa_modargs_free(ma
);
2212 pa_modargs_free(ma
);
2218 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2219 struct dbus_entry
*de
= p
;
2223 dbus_entry_free(de
);
2227 void pa__done(pa_module
*m
) {
2232 if (!(u
= m
->userdata
))
2236 if (u
->dbus_protocol
) {
2237 pa_assert(u
->dbus_entries
);
2239 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2240 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2242 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2244 pa_dbus_protocol_unref(u
->dbus_protocol
);
2248 if (u
->subscription
)
2249 pa_subscription_free(u
->subscription
);
2251 if (u
->sink_input_new_hook_slot
)
2252 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2253 if (u
->sink_input_fixate_hook_slot
)
2254 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2255 if (u
->source_output_new_hook_slot
)
2256 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2258 if (u
->sink_put_hook_slot
)
2259 pa_hook_slot_free(u
->sink_put_hook_slot
);
2260 if (u
->source_put_hook_slot
)
2261 pa_hook_slot_free(u
->source_put_hook_slot
);
2263 if (u
->sink_unlink_hook_slot
)
2264 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2265 if (u
->source_unlink_hook_slot
)
2266 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2268 if (u
->connection_unlink_hook_slot
)
2269 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2271 if (u
->save_time_event
)
2272 u
->core
->mainloop
->time_free(u
->save_time_event
);
2275 pa_database_close(u
->database
);
2278 pa_native_protocol_remove_ext(u
->protocol
, m
);
2279 pa_native_protocol_unref(u
->protocol
);
2283 pa_idxset_free(u
->subscribed
, NULL
, NULL
);