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
,
93 *source_output_fixate_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
);
334 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
335 * are a channel position and a volume value, respectively. The result is
336 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
337 * element. If the data is invalid, an error reply is sent and a negative
338 * number is returned. In case of a failure we make no guarantees about the
339 * state of map and vol. In case of an empty array the channels field of both
340 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
341 * before returning. */
342 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
343 DBusMessageIter array_iter
;
344 DBusMessageIter struct_iter
;
349 pa_assert(pa_streq(dbus_message_iter_get_signature(iter
), "a(uu)"));
353 pa_channel_map_init(map
);
354 pa_cvolume_init(vol
);
359 dbus_message_iter_recurse(iter
, &array_iter
);
361 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
362 dbus_uint32_t chan_pos
;
363 dbus_uint32_t chan_vol
;
365 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
367 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
369 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
370 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
374 pa_assert_se(dbus_message_iter_next(&struct_iter
));
375 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
377 if (!PA_VOLUME_IS_VALID(chan_vol
)) {
378 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
382 if (map
->channels
< PA_CHANNELS_MAX
) {
383 map
->map
[map
->channels
] = chan_pos
;
384 vol
->values
[map
->channels
] = chan_vol
;
389 dbus_message_iter_next(&array_iter
);
392 if (map
->channels
> PA_CHANNELS_MAX
) {
393 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
397 dbus_message_iter_next(iter
);
402 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
403 DBusMessageIter array_iter
;
404 DBusMessageIter struct_iter
;
410 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
412 if (!e
->volume_valid
) {
413 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
417 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
418 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
420 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
421 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
423 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
426 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
429 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
430 DBusMessageIter variant_iter
;
435 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
437 append_volume(&variant_iter
, e
);
439 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
442 static void send_new_entry_signal(struct dbus_entry
*entry
) {
443 DBusMessage
*signal_msg
;
447 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
448 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
449 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
450 dbus_message_unref(signal_msg
);
453 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
454 DBusMessage
*signal_msg
;
458 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
459 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
460 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
461 dbus_message_unref(signal_msg
);
464 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
465 DBusMessage
*signal_msg
;
471 device
= e
->device_valid
? e
->device
: "";
473 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
474 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
475 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
476 dbus_message_unref(signal_msg
);
479 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
480 DBusMessage
*signal_msg
;
481 DBusMessageIter msg_iter
;
486 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
487 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
488 append_volume(&msg_iter
, e
);
489 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
490 dbus_message_unref(signal_msg
);
493 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
494 DBusMessage
*signal_msg
;
500 pa_assert(e
->muted_valid
);
504 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
505 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
506 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
507 dbus_message_unref(signal_msg
);
510 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
511 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
516 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
519 /* The caller frees the array, but not the strings. */
520 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
521 const char **entries
;
524 struct dbus_entry
*de
;
529 *n
= pa_hashmap_size(u
->dbus_entries
);
534 entries
= pa_xnew(const char *, *n
);
536 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
)
537 entries
[i
++] = de
->object_path
;
542 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
543 struct userdata
*u
= userdata
;
544 const char **entries
;
551 entries
= get_entries(u
, &n
);
553 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
558 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
559 struct userdata
*u
= userdata
;
560 DBusMessage
*reply
= NULL
;
561 DBusMessageIter msg_iter
;
562 DBusMessageIter dict_iter
;
563 dbus_uint32_t interface_revision
;
564 const char **entries
;
571 interface_revision
= DBUS_INTERFACE_REVISION
;
572 entries
= get_entries(u
, &n_entries
);
574 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
576 dbus_message_iter_init_append(reply
, &msg_iter
);
577 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
579 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
580 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
582 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
584 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
586 dbus_message_unref(reply
);
591 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
592 struct userdata
*u
= userdata
;
593 DBusMessageIter msg_iter
;
594 const char *name
= NULL
;
595 const char *device
= NULL
;
598 dbus_bool_t muted
= FALSE
;
599 dbus_bool_t apply_immediately
= FALSE
;
600 struct dbus_entry
*dbus_entry
= NULL
;
601 struct entry
*e
= NULL
;
607 pa_assert_se(dbus_message_iter_init(msg
, &msg_iter
));
608 dbus_message_iter_get_basic(&msg_iter
, &name
);
610 pa_assert_se(dbus_message_iter_next(&msg_iter
));
611 dbus_message_iter_get_basic(&msg_iter
, &device
);
613 pa_assert_se(dbus_message_iter_next(&msg_iter
));
614 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
617 dbus_message_iter_get_basic(&msg_iter
, &muted
);
619 pa_assert_se(dbus_message_iter_next(&msg_iter
));
620 dbus_message_iter_get_basic(&msg_iter
, &apply_immediately
);
623 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
627 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
628 pa_bool_t mute_updated
= FALSE
;
629 pa_bool_t volume_updated
= FALSE
;
630 pa_bool_t device_updated
= FALSE
;
632 pa_assert_se(e
= entry_read(u
, name
));
633 mute_updated
= e
->muted
!= muted
;
635 e
->muted_valid
= TRUE
;
637 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
639 e
->channel_map
= map
;
640 e
->volume_valid
= !!map
.channels
;
642 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
644 e
->device
= pa_xstrdup(device
);
645 e
->device_valid
= !!device
[0];
648 send_mute_updated_signal(dbus_entry
, e
);
650 send_volume_updated_signal(dbus_entry
, e
);
652 send_device_updated_signal(dbus_entry
, e
);
655 dbus_entry
= dbus_entry_new(u
, name
);
656 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) == 0);
659 e
->muted_valid
= TRUE
;
660 e
->volume_valid
= !!map
.channels
;
661 e
->device_valid
= !!device
[0];
664 e
->channel_map
= map
;
665 e
->device
= pa_xstrdup(device
);
667 send_new_entry_signal(dbus_entry
);
670 pa_assert_se(entry_write(u
, name
, e
, TRUE
));
672 if (apply_immediately
)
673 entry_apply(u
, name
, e
);
677 pa_dbus_send_empty_reply(conn
, msg
);
682 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
683 struct userdata
*u
= userdata
;
685 struct dbus_entry
*de
;
691 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
));
693 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
694 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
698 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
701 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
702 struct dbus_entry
*de
= userdata
;
708 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
711 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
712 struct dbus_entry
*de
= userdata
;
718 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
721 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
722 struct dbus_entry
*de
= userdata
;
730 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
732 device
= e
->device_valid
? e
->device
: "";
734 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
739 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
740 struct dbus_entry
*de
= userdata
;
750 dbus_message_iter_get_basic(iter
, &device
);
752 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
754 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
758 e
->device
= pa_xstrdup(device
);
759 e
->device_valid
= !!device
[0];
761 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
763 entry_apply(de
->userdata
, de
->entry_name
, e
);
764 send_device_updated_signal(de
, e
);
765 trigger_save(de
->userdata
);
768 pa_dbus_send_empty_reply(conn
, msg
);
773 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
774 struct dbus_entry
*de
= userdata
;
776 DBusMessageIter msg_iter
;
783 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
785 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
787 dbus_message_iter_init_append(reply
, &msg_iter
);
788 append_volume_variant(&msg_iter
, e
);
790 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
795 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
796 struct dbus_entry
*de
= userdata
;
799 struct entry
*e
= NULL
;
800 pa_bool_t updated
= FALSE
;
807 if (get_volume_arg(conn
, msg
, iter
, &map
, &vol
) < 0)
810 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
812 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
816 e
->channel_map
= map
;
817 e
->volume_valid
= !!map
.channels
;
819 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
821 entry_apply(de
->userdata
, de
->entry_name
, e
);
822 send_volume_updated_signal(de
, e
);
823 trigger_save(de
->userdata
);
826 pa_dbus_send_empty_reply(conn
, msg
);
831 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
832 struct dbus_entry
*de
= userdata
;
840 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
842 mute
= e
->muted_valid
? e
->muted
: FALSE
;
844 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &mute
);
849 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
850 struct dbus_entry
*de
= userdata
;
860 dbus_message_iter_get_basic(iter
, &mute
);
862 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
864 updated
= !e
->muted_valid
|| e
->muted
!= mute
;
868 e
->muted_valid
= TRUE
;
870 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
872 entry_apply(de
->userdata
, de
->entry_name
, e
);
873 send_mute_updated_signal(de
, e
);
874 trigger_save(de
->userdata
);
877 pa_dbus_send_empty_reply(conn
, msg
);
882 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
883 struct dbus_entry
*de
= userdata
;
885 DBusMessage
*reply
= NULL
;
886 DBusMessageIter msg_iter
;
887 DBusMessageIter dict_iter
;
888 DBusMessageIter dict_entry_iter
;
896 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
898 device
= e
->device_valid
? e
->device
: "";
899 mute
= e
->muted_valid
? e
->muted
: FALSE
;
901 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
903 dbus_message_iter_init_append(reply
, &msg_iter
);
904 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
906 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
907 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
908 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
910 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
912 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
913 append_volume_variant(&dict_entry_iter
, e
);
915 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
917 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &mute
);
919 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
921 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
923 dbus_message_unref(reply
);
928 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
929 struct dbus_entry
*de
= userdata
;
936 key
.data
= de
->entry_name
;
937 key
.size
= strlen(de
->entry_name
);
939 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
941 send_entry_removed_signal(de
);
942 trigger_save(de
->userdata
);
944 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
947 pa_dbus_send_empty_reply(conn
, msg
);
950 #endif /* HAVE_DBUS */
952 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
953 struct userdata
*u
= userdata
;
959 pa_assert(e
== u
->save_time_event
);
960 u
->core
->mainloop
->time_free(u
->save_time_event
);
961 u
->save_time_event
= NULL
;
963 pa_database_sync(u
->database
);
964 pa_log_info("Synced.");
967 static char *get_name(pa_proplist
*p
, const char *prefix
) {
974 if ((r
= pa_proplist_gets(p
, IDENTIFICATION_PROPERTY
)))
975 return pa_xstrdup(r
);
977 if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_ROLE
)))
978 t
= pa_sprintf_malloc("%s-by-media-role:%s", prefix
, r
);
979 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_ID
)))
980 t
= pa_sprintf_malloc("%s-by-application-id:%s", prefix
, r
);
981 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_NAME
)))
982 t
= pa_sprintf_malloc("%s-by-application-name:%s", prefix
, r
);
983 else if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
)))
984 t
= pa_sprintf_malloc("%s-by-media-name:%s", prefix
, r
);
986 t
= pa_sprintf_malloc("%s-fallback:%s", prefix
, r
);
988 pa_proplist_sets(p
, IDENTIFICATION_PROPERTY
, t
);
992 static struct entry
* entry_new(void) {
993 struct entry
*r
= pa_xnew0(struct entry
, 1);
994 r
->version
= ENTRY_VERSION
;
998 static void entry_free(struct entry
* e
) {
1001 pa_xfree(e
->device
);
1006 static pa_bool_t
entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, pa_bool_t replace
) {
1015 t
= pa_tagstruct_new(NULL
, 0);
1016 pa_tagstruct_putu8(t
, e
->version
);
1017 pa_tagstruct_put_boolean(t
, e
->volume_valid
);
1018 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
1019 pa_tagstruct_put_cvolume(t
, &e
->volume
);
1020 pa_tagstruct_put_boolean(t
, e
->muted_valid
);
1021 pa_tagstruct_put_boolean(t
, e
->muted
);
1022 pa_tagstruct_put_boolean(t
, e
->device_valid
);
1023 pa_tagstruct_puts(t
, e
->device
);
1024 pa_tagstruct_put_boolean(t
, e
->card_valid
);
1025 pa_tagstruct_puts(t
, e
->card
);
1027 key
.data
= (char *) name
;
1028 key
.size
= strlen(name
);
1030 data
.data
= (void*)pa_tagstruct_data(t
, &data
.size
);
1032 r
= (pa_database_set(u
->database
, &key
, &data
, replace
) == 0);
1034 pa_tagstruct_free(t
);
1039 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1041 #define LEGACY_ENTRY_VERSION 3
1042 static struct entry
* legacy_entry_read(struct userdata
*u
, pa_datum
*data
) {
1043 struct legacy_entry
{
1045 pa_bool_t muted_valid
:1, volume_valid
:1, device_valid
:1, card_valid
:1;
1047 pa_channel_map channel_map
;
1049 char device
[PA_NAME_MAX
];
1050 char card
[PA_NAME_MAX
];
1052 struct legacy_entry
*le
;
1058 if (data
->size
!= sizeof(struct legacy_entry
)) {
1059 pa_log_debug("Size does not match.");
1063 le
= (struct legacy_entry
*)data
->data
;
1065 if (le
->version
!= LEGACY_ENTRY_VERSION
) {
1066 pa_log_debug("Version mismatch.");
1070 if (!memchr(le
->device
, 0, sizeof(le
->device
))) {
1071 pa_log_warn("Device has missing NUL byte.");
1075 if (!memchr(le
->card
, 0, sizeof(le
->card
))) {
1076 pa_log_warn("Card has missing NUL byte.");
1081 e
->card
= pa_xstrdup(le
->card
);
1086 static struct entry
*entry_read(struct userdata
*u
, const char *name
) {
1088 struct entry
*e
= NULL
;
1089 pa_tagstruct
*t
= NULL
;
1090 const char *device
, *card
;
1095 key
.data
= (char*) name
;
1096 key
.size
= strlen(name
);
1100 if (!pa_database_get(u
->database
, &key
, &data
))
1103 t
= pa_tagstruct_new(data
.data
, data
.size
);
1106 if (pa_tagstruct_getu8(t
, &e
->version
) < 0 ||
1107 e
->version
> ENTRY_VERSION
||
1108 pa_tagstruct_get_boolean(t
, &e
->volume_valid
) < 0 ||
1109 pa_tagstruct_get_channel_map(t
, &e
->channel_map
) < 0 ||
1110 pa_tagstruct_get_cvolume(t
, &e
->volume
) < 0 ||
1111 pa_tagstruct_get_boolean(t
, &e
->muted_valid
) < 0 ||
1112 pa_tagstruct_get_boolean(t
, &e
->muted
) < 0 ||
1113 pa_tagstruct_get_boolean(t
, &e
->device_valid
) < 0 ||
1114 pa_tagstruct_gets(t
, &device
) < 0 ||
1115 pa_tagstruct_get_boolean(t
, &e
->card_valid
) < 0 ||
1116 pa_tagstruct_gets(t
, &card
) < 0) {
1121 e
->device
= pa_xstrdup(device
);
1122 e
->card
= pa_xstrdup(card
);
1124 if (!pa_tagstruct_eof(t
))
1127 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1128 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1132 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1133 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1137 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1138 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1142 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1143 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1147 pa_tagstruct_free(t
);
1148 pa_datum_free(&data
);
1154 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name
);
1159 pa_tagstruct_free(t
);
1161 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1162 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name
);
1163 if ((e
= legacy_entry_read(u
, &data
))) {
1164 pa_log_debug("Success. Saving new format for key: %s", name
);
1165 if (entry_write(u
, name
, e
, TRUE
))
1167 pa_datum_free(&data
);
1170 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name
);
1173 pa_datum_free(&data
);
1177 static struct entry
* entry_copy(const struct entry
*e
) {
1183 r
->device
= pa_xstrdup(e
->device
);
1184 r
->card
= pa_xstrdup(e
->card
);
1188 static void trigger_save(struct userdata
*u
) {
1189 pa_native_connection
*c
;
1192 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1195 t
= pa_tagstruct_new(NULL
, 0);
1196 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1197 pa_tagstruct_putu32(t
, 0);
1198 pa_tagstruct_putu32(t
, u
->module
->index
);
1199 pa_tagstruct_puts(t
, u
->module
->name
);
1200 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1202 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1205 if (u
->save_time_event
)
1208 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1211 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1217 if (a
->device_valid
!= b
->device_valid
||
1218 (a
->device_valid
&& !pa_streq(a
->device
, b
->device
)))
1221 if (a
->card_valid
!= b
->card_valid
||
1222 (a
->card_valid
&& !pa_streq(a
->card
, b
->card
)))
1225 if (a
->muted_valid
!= b
->muted_valid
||
1226 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1230 if (a
->volume_valid
!= b
->volume_valid
||
1231 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1237 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1238 struct userdata
*u
= userdata
;
1239 struct entry
*entry
, *old
= NULL
;
1242 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1243 * clutter these are defined here unconditionally. */
1244 pa_bool_t created_new_entry
= TRUE
;
1245 pa_bool_t device_updated
= FALSE
;
1246 pa_bool_t volume_updated
= FALSE
;
1247 pa_bool_t mute_updated
= FALSE
;
1250 struct dbus_entry
*de
= NULL
;
1256 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1257 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1258 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1259 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1262 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1263 pa_sink_input
*sink_input
;
1265 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1268 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1271 if ((old
= entry_read(u
, name
))) {
1272 entry
= entry_copy(old
);
1273 created_new_entry
= FALSE
;
1275 entry
= entry_new();
1277 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1278 pa_assert(sink_input
->volume_writable
);
1280 entry
->channel_map
= sink_input
->channel_map
;
1281 pa_sink_input_get_volume(sink_input
, &entry
->volume
, FALSE
);
1282 entry
->volume_valid
= TRUE
;
1284 volume_updated
= !created_new_entry
1285 && (!old
->volume_valid
1286 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1287 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1290 if (sink_input
->save_muted
) {
1291 entry
->muted
= pa_sink_input_get_mute(sink_input
);
1292 entry
->muted_valid
= TRUE
;
1294 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1297 if (sink_input
->save_sink
) {
1298 pa_xfree(entry
->device
);
1299 entry
->device
= pa_xstrdup(sink_input
->sink
->name
);
1300 entry
->device_valid
= TRUE
;
1302 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1303 if (sink_input
->sink
->card
) {
1304 pa_xfree(entry
->card
);
1305 entry
->card
= pa_xstrdup(sink_input
->sink
->card
->name
);
1306 entry
->card_valid
= TRUE
;
1311 pa_source_output
*source_output
;
1313 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1315 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1318 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1321 if ((old
= entry_read(u
, name
))) {
1322 entry
= entry_copy(old
);
1323 created_new_entry
= FALSE
;
1325 entry
= entry_new();
1327 if (source_output
->save_volume
&& pa_source_output_is_volume_readable(source_output
)) {
1328 pa_assert(source_output
->volume_writable
);
1330 entry
->channel_map
= source_output
->channel_map
;
1331 pa_source_output_get_volume(source_output
, &entry
->volume
, FALSE
);
1332 entry
->volume_valid
= TRUE
;
1334 volume_updated
= !created_new_entry
1335 && (!old
->volume_valid
1336 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1337 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1340 if (source_output
->save_muted
) {
1341 entry
->muted
= pa_source_output_get_mute(source_output
);
1342 entry
->muted_valid
= TRUE
;
1344 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1347 if (source_output
->save_source
) {
1348 pa_xfree(entry
->device
);
1349 entry
->device
= pa_xstrdup(source_output
->source
->name
);
1350 entry
->device_valid
= TRUE
;
1352 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1354 if (source_output
->source
->card
) {
1355 pa_xfree(entry
->card
);
1356 entry
->card
= pa_xstrdup(source_output
->source
->card
->name
);
1357 entry
->card_valid
= TRUE
;
1366 if (entries_equal(old
, entry
)) {
1376 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1378 if (entry_write(u
, name
, entry
, TRUE
))
1382 if (created_new_entry
) {
1383 de
= dbus_entry_new(u
, name
);
1384 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1385 send_new_entry_signal(de
);
1387 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1390 send_device_updated_signal(de
, entry
);
1392 send_volume_updated_signal(de
, entry
);
1394 send_mute_updated_signal(de
, entry
);
1402 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1407 pa_assert(new_data
);
1409 pa_assert(u
->restore_device
);
1411 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1415 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1416 else if ((e
= entry_read(u
, name
))) {
1419 if (e
->device_valid
)
1420 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1422 if (!s
&& e
->card_valid
) {
1425 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1426 s
= pa_idxset_first(card
->sinks
, NULL
);
1429 /* It might happen that a stream and a sink are set up at the
1430 same time, in which case we want to make sure we don't
1431 interfere with that */
1432 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1433 if (pa_sink_input_new_data_set_sink(new_data
, s
, TRUE
))
1434 pa_log_info("Restoring device for stream %s.", name
);
1444 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1449 pa_assert(new_data
);
1451 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1453 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1456 if ((e
= entry_read(u
, name
))) {
1458 if (u
->restore_volume
&& e
->volume_valid
) {
1459 if (!new_data
->volume_writable
)
1460 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1461 else if (new_data
->volume_is_set
)
1462 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1466 pa_log_info("Restoring volume for sink input %s.", name
);
1469 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1470 pa_sink_input_new_data_set_volume(new_data
, &v
);
1472 new_data
->volume_is_absolute
= FALSE
;
1473 new_data
->save_volume
= TRUE
;
1477 if (u
->restore_muted
&& e
->muted_valid
) {
1479 if (!new_data
->muted_is_set
) {
1480 pa_log_info("Restoring mute state for sink input %s.", name
);
1481 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1482 new_data
->save_muted
= TRUE
;
1484 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1495 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1500 pa_assert(new_data
);
1502 pa_assert(u
->restore_device
);
1504 if (new_data
->direct_on_input
)
1507 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1510 if (new_data
->source
)
1511 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1512 else if ((e
= entry_read(u
, name
))) {
1513 pa_source
*s
= NULL
;
1515 if (e
->device_valid
)
1516 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1518 if (!s
&& e
->card_valid
) {
1521 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1522 s
= pa_idxset_first(card
->sources
, NULL
);
1525 /* It might happen that a stream and a sink are set up at the
1526 same time, in which case we want to make sure we don't
1527 interfere with that */
1528 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1529 pa_log_info("Restoring device for stream %s.", name
);
1530 pa_source_output_new_data_set_source(new_data
, s
, TRUE
);
1541 static pa_hook_result_t
source_output_fixate_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1546 pa_assert(new_data
);
1548 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1550 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1553 if ((e
= entry_read(u
, name
))) {
1555 if (u
->restore_volume
&& e
->volume_valid
) {
1556 if (!new_data
->volume_writable
)
1557 pa_log_debug("Not restoring volume for source output %s, because its volume can't be changed.", name
);
1558 else if (new_data
->volume_is_set
)
1559 pa_log_debug("Not restoring volume for source output %s, because already set.", name
);
1563 pa_log_info("Restoring volume for source output %s.", name
);
1566 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1567 pa_source_output_new_data_set_volume(new_data
, &v
);
1569 new_data
->volume_is_absolute
= FALSE
;
1570 new_data
->save_volume
= TRUE
;
1574 if (u
->restore_muted
&& e
->muted_valid
) {
1576 if (!new_data
->muted_is_set
) {
1577 pa_log_info("Restoring mute state for source output %s.", name
);
1578 pa_source_output_new_data_set_muted(new_data
, e
->muted
);
1579 new_data
->save_muted
= TRUE
;
1581 pa_log_debug("Not restoring mute state for source output %s, because already set.", name
);
1592 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1599 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1601 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1605 if (si
->sink
== sink
)
1611 /* Skip this if it is already in the process of being moved
1616 /* It might happen that a stream and a sink are set up at the
1617 same time, in which case we want to make sure we don't
1618 interfere with that */
1619 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1622 if (!(name
= get_name(si
->proplist
, "sink-input")))
1625 if ((e
= entry_read(u
, name
))) {
1626 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1627 pa_sink_input_move_to(si
, sink
, TRUE
);
1638 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1639 pa_source_output
*so
;
1645 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1647 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1651 if (so
->source
== source
)
1654 if (so
->save_source
)
1657 if (so
->direct_on_input
)
1660 /* Skip this if it is already in the process of being moved anyway */
1664 /* It might happen that a stream and a source are set up at the
1665 same time, in which case we want to make sure we don't
1666 interfere with that */
1667 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1670 if (!(name
= get_name(so
->proplist
, "source-output")))
1673 if ((e
= entry_read(u
, name
))) {
1674 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1675 pa_source_output_move_to(so
, source
, TRUE
);
1686 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1693 pa_assert(u
->on_rescue
&& u
->restore_device
);
1695 /* There's no point in doing anything if the core is shut down anyway */
1696 if (c
->state
== PA_CORE_SHUTDOWN
)
1699 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1706 if (!(name
= get_name(si
->proplist
, "sink-input")))
1709 if ((e
= entry_read(u
, name
))) {
1711 if (e
->device_valid
) {
1714 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1716 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1717 pa_sink_input_move_to(si
, d
, TRUE
);
1729 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1730 pa_source_output
*so
;
1736 pa_assert(u
->on_rescue
&& u
->restore_device
);
1738 /* There's no point in doing anything if the core is shut down anyway */
1739 if (c
->state
== PA_CORE_SHUTDOWN
)
1742 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1746 if (so
->direct_on_input
)
1752 if (!(name
= get_name(so
->proplist
, "source-output")))
1755 if ((e
= entry_read(u
, name
))) {
1757 if (e
->device_valid
) {
1760 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1762 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1763 pa_source_output_move_to(so
, d
, TRUE
);
1775 #define EXT_VERSION 1
1777 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
) {
1779 pa_source_output
*so
;
1786 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1790 if (!(n
= get_name(si
->proplist
, "sink-input")))
1793 if (!pa_streq(name
, n
)) {
1799 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1803 pa_log_info("Restoring volume for sink input %s.", name
);
1804 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1805 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1808 if (u
->restore_muted
&& e
->muted_valid
) {
1809 pa_log_info("Restoring mute state for sink input %s.", name
);
1810 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1813 if (u
->restore_device
) {
1814 if (!e
->device_valid
) {
1815 if (si
->save_sink
) {
1816 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1817 /* If the device is not valid we should make sure the
1818 save flag is cleared as the user may have specifically
1819 removed the sink element from the rule. */
1820 si
->save_sink
= FALSE
;
1821 /* This is cheating a bit. The sink input itself has not changed
1822 but the rules governing it's routing have, so we fire this event
1823 such that other routing modules (e.g. module-device-manager)
1824 will pick up the change and reapply their routing */
1825 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1827 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1828 pa_log_info("Restoring device for stream %s.", name
);
1829 pa_sink_input_move_to(si
, s
, TRUE
);
1834 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1838 if (!(n
= get_name(so
->proplist
, "source-output")))
1841 if (!pa_streq(name
, n
)) {
1847 if (u
->restore_volume
&& e
->volume_valid
&& so
->volume_writable
) {
1851 pa_log_info("Restoring volume for source output %s.", name
);
1852 pa_cvolume_remap(&v
, &e
->channel_map
, &so
->channel_map
);
1853 pa_source_output_set_volume(so
, &v
, TRUE
, FALSE
);
1856 if (u
->restore_muted
&& e
->muted_valid
) {
1857 pa_log_info("Restoring mute state for source output %s.", name
);
1858 pa_source_output_set_mute(so
, e
->muted
, TRUE
);
1861 if (u
->restore_device
) {
1862 if (!e
->device_valid
) {
1863 if (so
->save_source
) {
1864 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1865 /* If the device is not valid we should make sure the
1866 save flag is cleared as the user may have specifically
1867 removed the source element from the rule. */
1868 so
->save_source
= FALSE
;
1869 /* This is cheating a bit. The source output itself has not changed
1870 but the rules governing it's routing have, so we fire this event
1871 such that other routing modules (e.g. module-device-manager)
1872 will pick up the change and reapply their routing */
1873 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1875 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1876 pa_log_info("Restoring device for stream %s.", name
);
1877 pa_source_output_move_to(so
, s
, TRUE
);
1884 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1888 done
= !pa_database_first(u
->database
, &key
, NULL
);
1895 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1897 name
= pa_xstrndup(key
.data
, key
.size
);
1898 pa_datum_free(&key
);
1900 if ((e
= entry_read(u
, name
))) {
1902 pa_log("name=%s", name
);
1903 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1904 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1905 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1906 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1917 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1920 pa_tagstruct
*reply
= NULL
;
1929 if (pa_tagstruct_getu32(t
, &command
) < 0)
1932 reply
= pa_tagstruct_new(NULL
, 0);
1933 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1934 pa_tagstruct_putu32(reply
, tag
);
1937 case SUBCOMMAND_TEST
: {
1938 if (!pa_tagstruct_eof(t
))
1941 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1945 case SUBCOMMAND_READ
: {
1949 if (!pa_tagstruct_eof(t
))
1952 done
= !pa_database_first(u
->database
, &key
, NULL
);
1959 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1961 name
= pa_xstrndup(key
.data
, key
.size
);
1962 pa_datum_free(&key
);
1964 if ((e
= entry_read(u
, name
))) {
1968 pa_tagstruct_puts(reply
, name
);
1969 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1970 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1971 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1972 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1985 case SUBCOMMAND_WRITE
: {
1987 pa_bool_t apply_immediately
= FALSE
;
1989 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1990 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1993 if (mode
!= PA_UPDATE_MERGE
&&
1994 mode
!= PA_UPDATE_REPLACE
&&
1995 mode
!= PA_UPDATE_SET
)
1998 if (mode
== PA_UPDATE_SET
) {
2000 struct dbus_entry
*de
;
2003 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
2004 send_entry_removed_signal(de
);
2005 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
2008 pa_database_clear(u
->database
);
2011 while (!pa_tagstruct_eof(t
)) {
2012 const char *name
, *device
;
2014 struct entry
*entry
;
2019 entry
= entry_new();
2021 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2022 pa_tagstruct_get_channel_map(t
, &entry
->channel_map
) ||
2023 pa_tagstruct_get_cvolume(t
, &entry
->volume
) < 0 ||
2024 pa_tagstruct_gets(t
, &device
) < 0 ||
2025 pa_tagstruct_get_boolean(t
, &muted
) < 0)
2028 if (!name
|| !*name
) {
2033 entry
->volume_valid
= entry
->volume
.channels
> 0;
2035 if (entry
->volume_valid
)
2036 if (!pa_cvolume_compatible_with_channel_map(&entry
->volume
, &entry
->channel_map
)) {
2041 entry
->muted
= muted
;
2042 entry
->muted_valid
= TRUE
;
2044 entry
->device
= pa_xstrdup(device
);
2045 entry
->device_valid
= device
&& !!entry
->device
[0];
2047 if (entry
->device_valid
&& !pa_namereg_is_valid_name(entry
->device
)) {
2053 old
= entry_read(u
, name
);
2056 pa_log_debug("Client %s changes entry %s.",
2057 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
2060 if (entry_write(u
, name
, entry
, mode
== PA_UPDATE_REPLACE
)) {
2062 struct dbus_entry
*de
;
2065 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
2067 if ((old
->device_valid
!= entry
->device_valid
)
2068 || (entry
->device_valid
&& !pa_streq(entry
->device
, old
->device
)))
2069 send_device_updated_signal(de
, entry
);
2071 if ((old
->volume_valid
!= entry
->volume_valid
)
2072 || (entry
->volume_valid
&& (!pa_cvolume_equal(&entry
->volume
, &old
->volume
)
2073 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
))))
2074 send_volume_updated_signal(de
, entry
);
2076 if (!old
->muted_valid
|| (entry
->muted
!= old
->muted
))
2077 send_mute_updated_signal(de
, entry
);
2080 de
= dbus_entry_new(u
, name
);
2081 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2082 send_new_entry_signal(de
);
2086 if (apply_immediately
)
2087 entry_apply(u
, name
, entry
);
2102 case SUBCOMMAND_DELETE
:
2104 while (!pa_tagstruct_eof(t
)) {
2108 struct dbus_entry
*de
;
2111 if (pa_tagstruct_gets(t
, &name
) < 0)
2115 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
2116 send_entry_removed_signal(de
);
2117 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
2121 key
.data
= (char*) name
;
2122 key
.size
= strlen(name
);
2124 pa_database_unset(u
->database
, &key
);
2131 case SUBCOMMAND_SUBSCRIBE
: {
2135 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
2136 !pa_tagstruct_eof(t
))
2140 pa_idxset_put(u
->subscribed
, c
, NULL
);
2142 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2151 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
2157 pa_tagstruct_free(reply
);
2162 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
2167 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2171 int pa__init(pa_module
*m
) {
2172 pa_modargs
*ma
= NULL
;
2176 pa_source_output
*so
;
2178 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
2186 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2187 pa_log("Failed to parse module arguments");
2191 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2192 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2193 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2194 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2195 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2196 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2200 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2201 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2203 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2206 u
->restore_device
= restore_device
;
2207 u
->restore_volume
= restore_volume
;
2208 u
->restore_muted
= restore_muted
;
2209 u
->on_hotplug
= on_hotplug
;
2210 u
->on_rescue
= on_rescue
;
2211 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2213 u
->protocol
= pa_native_protocol_get(m
->core
);
2214 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2216 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
);
2218 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2220 if (restore_device
) {
2221 /* A little bit earlier than module-intended-roles ... */
2222 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
);
2223 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
);
2226 if (restore_device
&& on_hotplug
) {
2227 /* A little bit earlier than module-intended-roles ... */
2228 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
);
2229 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
);
2232 if (restore_device
&& on_rescue
) {
2233 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2234 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
);
2235 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
);
2238 if (restore_volume
|| restore_muted
) {
2239 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
);
2240 u
->source_output_fixate_hook_slot
= pa_hook_connect(&m
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE
], PA_HOOK_EARLY
, (pa_hook_cb_t
) source_output_fixate_hook_callback
, u
);
2243 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2246 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2247 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2252 pa_log_info("Successfully opened database file '%s'.", fname
);
2256 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2257 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2259 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2260 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2262 /* Create the initial dbus entries. */
2263 done
= !pa_database_first(u
->database
, &key
, NULL
);
2267 struct dbus_entry
*de
;
2270 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2272 name
= pa_xstrndup(key
.data
, key
.size
);
2273 pa_datum_free(&key
);
2275 /* Use entry_read() for checking that the entry is valid. */
2276 if ((e
= entry_read(u
, name
))) {
2277 de
= dbus_entry_new(u
, name
);
2278 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2288 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2289 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2291 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2292 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2294 pa_modargs_free(ma
);
2301 pa_modargs_free(ma
);
2307 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2308 struct dbus_entry
*de
= p
;
2312 dbus_entry_free(de
);
2316 void pa__done(pa_module
*m
) {
2321 if (!(u
= m
->userdata
))
2325 if (u
->dbus_protocol
) {
2326 pa_assert(u
->dbus_entries
);
2328 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2329 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2331 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2333 pa_dbus_protocol_unref(u
->dbus_protocol
);
2337 if (u
->subscription
)
2338 pa_subscription_free(u
->subscription
);
2340 if (u
->sink_input_new_hook_slot
)
2341 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2342 if (u
->sink_input_fixate_hook_slot
)
2343 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2344 if (u
->source_output_new_hook_slot
)
2345 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2346 if (u
->source_output_fixate_hook_slot
)
2347 pa_hook_slot_free(u
->source_output_fixate_hook_slot
);
2349 if (u
->sink_put_hook_slot
)
2350 pa_hook_slot_free(u
->sink_put_hook_slot
);
2351 if (u
->source_put_hook_slot
)
2352 pa_hook_slot_free(u
->source_put_hook_slot
);
2354 if (u
->sink_unlink_hook_slot
)
2355 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2356 if (u
->source_unlink_hook_slot
)
2357 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2359 if (u
->connection_unlink_hook_slot
)
2360 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2362 if (u
->save_time_event
)
2363 u
->core
->mainloop
->time_free(u
->save_time_event
);
2366 pa_database_close(u
->database
);
2369 pa_native_protocol_remove_ext(u
->protocol
, m
);
2370 pa_native_protocol_unref(u
->protocol
);
2374 pa_idxset_free(u
->subscribed
, NULL
, NULL
);