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
);
333 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
334 * are a channel position and a volume value, respectively. The result is
335 * stored in the map and vol arguments. The iterator must point to a "a(uu)"
336 * element. If the data is invalid, an error reply is sent and a negative
337 * number is returned. In case of a failure we make no guarantees about the
338 * state of map and vol. In case of an empty array the channels field of both
339 * map and vol are set to 0. This function calls dbus_message_iter_next(iter)
340 * before returning. */
341 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
342 DBusMessageIter array_iter
;
343 DBusMessageIter struct_iter
;
348 pa_assert(pa_streq(dbus_message_iter_get_signature(iter
), "a(uu)"));
352 pa_channel_map_init(map
);
353 pa_cvolume_init(vol
);
358 dbus_message_iter_recurse(iter
, &array_iter
);
360 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
361 dbus_uint32_t chan_pos
;
362 dbus_uint32_t chan_vol
;
364 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
366 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
368 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
369 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
373 pa_assert_se(dbus_message_iter_next(&struct_iter
));
374 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
376 if (!PA_VOLUME_IS_VALID(chan_vol
)) {
377 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
381 if (map
->channels
< PA_CHANNELS_MAX
) {
382 map
->map
[map
->channels
] = chan_pos
;
383 vol
->values
[map
->channels
] = chan_vol
;
388 dbus_message_iter_next(&array_iter
);
391 if (map
->channels
> PA_CHANNELS_MAX
) {
392 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
396 dbus_message_iter_next(iter
);
401 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
402 DBusMessageIter array_iter
;
403 DBusMessageIter struct_iter
;
409 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
411 if (!e
->volume_valid
) {
412 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
416 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
417 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
419 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
420 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
422 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
425 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
428 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
429 DBusMessageIter variant_iter
;
434 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
436 append_volume(&variant_iter
, e
);
438 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
441 static void send_new_entry_signal(struct dbus_entry
*entry
) {
442 DBusMessage
*signal_msg
;
446 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
447 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
448 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
449 dbus_message_unref(signal_msg
);
452 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
453 DBusMessage
*signal_msg
;
457 pa_assert_se(signal_msg
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
458 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
459 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal_msg
);
460 dbus_message_unref(signal_msg
);
463 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
464 DBusMessage
*signal_msg
;
470 device
= e
->device_valid
? e
->device
: "";
472 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
473 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
474 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
475 dbus_message_unref(signal_msg
);
478 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
479 DBusMessage
*signal_msg
;
480 DBusMessageIter msg_iter
;
485 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
486 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
487 append_volume(&msg_iter
, e
);
488 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
489 dbus_message_unref(signal_msg
);
492 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
493 DBusMessage
*signal_msg
;
499 pa_assert(e
->muted_valid
);
503 pa_assert_se(signal_msg
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
504 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
505 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal_msg
);
506 dbus_message_unref(signal_msg
);
509 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
510 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
515 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
518 /* The caller frees the array, but not the strings. */
519 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
520 const char **entries
;
523 struct dbus_entry
*de
;
528 *n
= pa_hashmap_size(u
->dbus_entries
);
533 entries
= pa_xnew(const char *, *n
);
535 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
)
536 entries
[i
++] = de
->object_path
;
541 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
542 struct userdata
*u
= userdata
;
543 const char **entries
;
550 entries
= get_entries(u
, &n
);
552 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
557 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
558 struct userdata
*u
= userdata
;
559 DBusMessage
*reply
= NULL
;
560 DBusMessageIter msg_iter
;
561 DBusMessageIter dict_iter
;
562 dbus_uint32_t interface_revision
;
563 const char **entries
;
570 interface_revision
= DBUS_INTERFACE_REVISION
;
571 entries
= get_entries(u
, &n_entries
);
573 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
575 dbus_message_iter_init_append(reply
, &msg_iter
);
576 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
578 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
579 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
581 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
583 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
585 dbus_message_unref(reply
);
590 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
591 struct userdata
*u
= userdata
;
592 DBusMessageIter msg_iter
;
593 const char *name
= NULL
;
594 const char *device
= NULL
;
597 dbus_bool_t muted
= FALSE
;
598 dbus_bool_t apply_immediately
= FALSE
;
599 struct dbus_entry
*dbus_entry
= NULL
;
600 struct entry
*e
= NULL
;
606 pa_assert_se(dbus_message_iter_init(msg
, &msg_iter
));
607 dbus_message_iter_get_basic(&msg_iter
, &name
);
609 pa_assert_se(dbus_message_iter_next(&msg_iter
));
610 dbus_message_iter_get_basic(&msg_iter
, &device
);
612 pa_assert_se(dbus_message_iter_next(&msg_iter
));
613 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
616 dbus_message_iter_get_basic(&msg_iter
, &muted
);
618 pa_assert_se(dbus_message_iter_next(&msg_iter
));
619 dbus_message_iter_get_basic(&msg_iter
, &apply_immediately
);
622 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
626 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
627 pa_bool_t mute_updated
= FALSE
;
628 pa_bool_t volume_updated
= FALSE
;
629 pa_bool_t device_updated
= FALSE
;
631 pa_assert_se(e
= entry_read(u
, name
));
632 mute_updated
= e
->muted
!= muted
;
634 e
->muted_valid
= TRUE
;
636 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
638 e
->channel_map
= map
;
639 e
->volume_valid
= !!map
.channels
;
641 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
643 e
->device
= pa_xstrdup(device
);
644 e
->device_valid
= !!device
[0];
647 send_mute_updated_signal(dbus_entry
, e
);
649 send_volume_updated_signal(dbus_entry
, e
);
651 send_device_updated_signal(dbus_entry
, e
);
654 dbus_entry
= dbus_entry_new(u
, name
);
655 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) == 0);
658 e
->muted_valid
= TRUE
;
659 e
->volume_valid
= !!map
.channels
;
660 e
->device_valid
= !!device
[0];
663 e
->channel_map
= map
;
664 e
->device
= pa_xstrdup(device
);
666 send_new_entry_signal(dbus_entry
);
669 pa_assert_se(entry_write(u
, name
, e
, TRUE
));
671 if (apply_immediately
)
672 entry_apply(u
, name
, e
);
676 pa_dbus_send_empty_reply(conn
, msg
);
681 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
682 struct userdata
*u
= userdata
;
684 struct dbus_entry
*de
;
690 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
));
692 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
693 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
697 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
700 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
701 struct dbus_entry
*de
= userdata
;
707 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
710 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
711 struct dbus_entry
*de
= userdata
;
717 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
720 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
721 struct dbus_entry
*de
= userdata
;
729 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
731 device
= e
->device_valid
? e
->device
: "";
733 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
738 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
739 struct dbus_entry
*de
= userdata
;
749 dbus_message_iter_get_basic(iter
, &device
);
751 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
753 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
757 e
->device
= pa_xstrdup(device
);
758 e
->device_valid
= !!device
[0];
760 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
762 entry_apply(de
->userdata
, de
->entry_name
, e
);
763 send_device_updated_signal(de
, e
);
764 trigger_save(de
->userdata
);
767 pa_dbus_send_empty_reply(conn
, msg
);
772 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
773 struct dbus_entry
*de
= userdata
;
775 DBusMessageIter msg_iter
;
782 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
784 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
786 dbus_message_iter_init_append(reply
, &msg_iter
);
787 append_volume_variant(&msg_iter
, e
);
789 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
794 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
795 struct dbus_entry
*de
= userdata
;
798 struct entry
*e
= NULL
;
799 pa_bool_t updated
= FALSE
;
806 if (get_volume_arg(conn
, msg
, iter
, &map
, &vol
) < 0)
809 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
811 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
815 e
->channel_map
= map
;
816 e
->volume_valid
= !!map
.channels
;
818 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
820 entry_apply(de
->userdata
, de
->entry_name
, e
);
821 send_volume_updated_signal(de
, e
);
822 trigger_save(de
->userdata
);
825 pa_dbus_send_empty_reply(conn
, msg
);
830 static void handle_entry_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
831 struct dbus_entry
*de
= userdata
;
839 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
841 mute
= e
->muted_valid
? e
->muted
: FALSE
;
843 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &mute
);
848 static void handle_entry_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
849 struct dbus_entry
*de
= userdata
;
859 dbus_message_iter_get_basic(iter
, &mute
);
861 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
863 updated
= !e
->muted_valid
|| e
->muted
!= mute
;
867 e
->muted_valid
= TRUE
;
869 pa_assert_se(entry_write(de
->userdata
, de
->entry_name
, e
, TRUE
));
871 entry_apply(de
->userdata
, de
->entry_name
, e
);
872 send_mute_updated_signal(de
, e
);
873 trigger_save(de
->userdata
);
876 pa_dbus_send_empty_reply(conn
, msg
);
881 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
882 struct dbus_entry
*de
= userdata
;
884 DBusMessage
*reply
= NULL
;
885 DBusMessageIter msg_iter
;
886 DBusMessageIter dict_iter
;
887 DBusMessageIter dict_entry_iter
;
895 pa_assert_se(e
= entry_read(de
->userdata
, de
->entry_name
));
897 device
= e
->device_valid
? e
->device
: "";
898 mute
= e
->muted_valid
? e
->muted
: FALSE
;
900 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
902 dbus_message_iter_init_append(reply
, &msg_iter
);
903 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
905 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
906 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
907 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
909 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
911 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
912 append_volume_variant(&dict_entry_iter
, e
);
914 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
916 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &mute
);
918 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
920 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
922 dbus_message_unref(reply
);
927 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
928 struct dbus_entry
*de
= userdata
;
935 key
.data
= de
->entry_name
;
936 key
.size
= strlen(de
->entry_name
);
938 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
940 send_entry_removed_signal(de
);
941 trigger_save(de
->userdata
);
943 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
946 pa_dbus_send_empty_reply(conn
, msg
);
949 #endif /* HAVE_DBUS */
951 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
952 struct userdata
*u
= userdata
;
958 pa_assert(e
== u
->save_time_event
);
959 u
->core
->mainloop
->time_free(u
->save_time_event
);
960 u
->save_time_event
= NULL
;
962 pa_database_sync(u
->database
);
963 pa_log_info("Synced.");
966 static char *get_name(pa_proplist
*p
, const char *prefix
) {
973 if ((r
= pa_proplist_gets(p
, IDENTIFICATION_PROPERTY
)))
974 return pa_xstrdup(r
);
976 if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_ROLE
)))
977 t
= pa_sprintf_malloc("%s-by-media-role:%s", prefix
, r
);
978 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_ID
)))
979 t
= pa_sprintf_malloc("%s-by-application-id:%s", prefix
, r
);
980 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_NAME
)))
981 t
= pa_sprintf_malloc("%s-by-application-name:%s", prefix
, r
);
982 else if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
)))
983 t
= pa_sprintf_malloc("%s-by-media-name:%s", prefix
, r
);
985 t
= pa_sprintf_malloc("%s-fallback:%s", prefix
, r
);
987 pa_proplist_sets(p
, IDENTIFICATION_PROPERTY
, t
);
991 static struct entry
* entry_new(void) {
992 struct entry
*r
= pa_xnew0(struct entry
, 1);
993 r
->version
= ENTRY_VERSION
;
997 static void entry_free(struct entry
* e
) {
1000 pa_xfree(e
->device
);
1005 static pa_bool_t
entry_write(struct userdata
*u
, const char *name
, const struct entry
*e
, pa_bool_t replace
) {
1014 t
= pa_tagstruct_new(NULL
, 0);
1015 pa_tagstruct_putu8(t
, e
->version
);
1016 pa_tagstruct_put_boolean(t
, e
->volume_valid
);
1017 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
1018 pa_tagstruct_put_cvolume(t
, &e
->volume
);
1019 pa_tagstruct_put_boolean(t
, e
->muted_valid
);
1020 pa_tagstruct_put_boolean(t
, e
->muted
);
1021 pa_tagstruct_put_boolean(t
, e
->device_valid
);
1022 pa_tagstruct_puts(t
, e
->device
);
1023 pa_tagstruct_put_boolean(t
, e
->card_valid
);
1024 pa_tagstruct_puts(t
, e
->card
);
1026 key
.data
= (char *) name
;
1027 key
.size
= strlen(name
);
1029 data
.data
= (void*)pa_tagstruct_data(t
, &data
.size
);
1031 r
= (pa_database_set(u
->database
, &key
, &data
, replace
) == 0);
1033 pa_tagstruct_free(t
);
1038 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1040 #define LEGACY_ENTRY_VERSION 3
1041 static struct entry
* legacy_entry_read(struct userdata
*u
, pa_datum
*data
) {
1042 struct legacy_entry
{
1044 pa_bool_t muted_valid
:1, volume_valid
:1, device_valid
:1, card_valid
:1;
1046 pa_channel_map channel_map
;
1048 char device
[PA_NAME_MAX
];
1049 char card
[PA_NAME_MAX
];
1051 struct legacy_entry
*le
;
1057 if (data
->size
!= sizeof(struct legacy_entry
)) {
1058 pa_log_debug("Size does not match.");
1062 le
= (struct legacy_entry
*)data
->data
;
1064 if (le
->version
!= LEGACY_ENTRY_VERSION
) {
1065 pa_log_debug("Version mismatch.");
1069 if (!memchr(le
->device
, 0, sizeof(le
->device
))) {
1070 pa_log_warn("Device has missing NUL byte.");
1074 if (!memchr(le
->card
, 0, sizeof(le
->card
))) {
1075 pa_log_warn("Card has missing NUL byte.");
1080 e
->card
= pa_xstrdup(le
->card
);
1085 static struct entry
*entry_read(struct userdata
*u
, const char *name
) {
1087 struct entry
*e
= NULL
;
1088 pa_tagstruct
*t
= NULL
;
1089 const char *device
, *card
;
1094 key
.data
= (char*) name
;
1095 key
.size
= strlen(name
);
1099 if (!pa_database_get(u
->database
, &key
, &data
))
1102 t
= pa_tagstruct_new(data
.data
, data
.size
);
1105 if (pa_tagstruct_getu8(t
, &e
->version
) < 0 ||
1106 e
->version
> ENTRY_VERSION
||
1107 pa_tagstruct_get_boolean(t
, &e
->volume_valid
) < 0 ||
1108 pa_tagstruct_get_channel_map(t
, &e
->channel_map
) < 0 ||
1109 pa_tagstruct_get_cvolume(t
, &e
->volume
) < 0 ||
1110 pa_tagstruct_get_boolean(t
, &e
->muted_valid
) < 0 ||
1111 pa_tagstruct_get_boolean(t
, &e
->muted
) < 0 ||
1112 pa_tagstruct_get_boolean(t
, &e
->device_valid
) < 0 ||
1113 pa_tagstruct_gets(t
, &device
) < 0 ||
1114 pa_tagstruct_get_boolean(t
, &e
->card_valid
) < 0 ||
1115 pa_tagstruct_gets(t
, &card
) < 0) {
1120 e
->device
= pa_xstrdup(device
);
1121 e
->card
= pa_xstrdup(card
);
1123 if (!pa_tagstruct_eof(t
))
1126 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1127 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1131 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1132 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1136 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1137 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1141 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1142 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1146 pa_tagstruct_free(t
);
1147 pa_datum_free(&data
);
1153 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name
);
1158 pa_tagstruct_free(t
);
1160 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1161 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name
);
1162 if ((e
= legacy_entry_read(u
, &data
))) {
1163 pa_log_debug("Success. Saving new format for key: %s", name
);
1164 if (entry_write(u
, name
, e
, TRUE
))
1166 pa_datum_free(&data
);
1169 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name
);
1172 pa_datum_free(&data
);
1176 static struct entry
* entry_copy(const struct entry
*e
) {
1182 r
->device
= pa_xstrdup(e
->device
);
1183 r
->card
= pa_xstrdup(e
->card
);
1187 static void trigger_save(struct userdata
*u
) {
1188 pa_native_connection
*c
;
1191 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1194 t
= pa_tagstruct_new(NULL
, 0);
1195 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1196 pa_tagstruct_putu32(t
, 0);
1197 pa_tagstruct_putu32(t
, u
->module
->index
);
1198 pa_tagstruct_puts(t
, u
->module
->name
);
1199 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1201 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1204 if (u
->save_time_event
)
1207 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1210 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1216 if (a
->device_valid
!= b
->device_valid
||
1217 (a
->device_valid
&& !pa_streq(a
->device
, b
->device
)))
1220 if (a
->card_valid
!= b
->card_valid
||
1221 (a
->card_valid
&& !pa_streq(a
->card
, b
->card
)))
1224 if (a
->muted_valid
!= b
->muted_valid
||
1225 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1229 if (a
->volume_valid
!= b
->volume_valid
||
1230 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1236 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1237 struct userdata
*u
= userdata
;
1238 struct entry
*entry
, *old
= NULL
;
1241 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1242 * clutter these are defined here unconditionally. */
1243 pa_bool_t created_new_entry
= TRUE
;
1244 pa_bool_t device_updated
= FALSE
;
1245 pa_bool_t volume_updated
= FALSE
;
1246 pa_bool_t mute_updated
= FALSE
;
1249 struct dbus_entry
*de
= NULL
;
1255 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1256 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1257 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1258 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1261 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1262 pa_sink_input
*sink_input
;
1264 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1267 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1270 if ((old
= entry_read(u
, name
))) {
1271 entry
= entry_copy(old
);
1272 created_new_entry
= FALSE
;
1274 entry
= entry_new();
1276 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1277 pa_assert(sink_input
->volume_writable
);
1279 entry
->channel_map
= sink_input
->channel_map
;
1280 pa_sink_input_get_volume(sink_input
, &entry
->volume
, FALSE
);
1281 entry
->volume_valid
= TRUE
;
1283 volume_updated
= !created_new_entry
1284 && (!old
->volume_valid
1285 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1286 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1289 if (sink_input
->save_muted
) {
1290 entry
->muted
= pa_sink_input_get_mute(sink_input
);
1291 entry
->muted_valid
= TRUE
;
1293 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1296 if (sink_input
->save_sink
) {
1297 pa_xfree(entry
->device
);
1298 entry
->device
= pa_xstrdup(sink_input
->sink
->name
);
1299 entry
->device_valid
= TRUE
;
1301 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1302 if (sink_input
->sink
->card
) {
1303 pa_xfree(entry
->card
);
1304 entry
->card
= pa_xstrdup(sink_input
->sink
->card
->name
);
1305 entry
->card_valid
= TRUE
;
1310 pa_source_output
*source_output
;
1312 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1314 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1317 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1320 if ((old
= entry_read(u
, name
))) {
1321 entry
= entry_copy(old
);
1322 created_new_entry
= FALSE
;
1324 entry
= entry_new();
1326 if (source_output
->save_volume
&& pa_source_output_is_volume_readable(source_output
)) {
1327 pa_assert(source_output
->volume_writable
);
1329 entry
->channel_map
= source_output
->channel_map
;
1330 pa_source_output_get_volume(source_output
, &entry
->volume
, FALSE
);
1331 entry
->volume_valid
= TRUE
;
1333 volume_updated
= !created_new_entry
1334 && (!old
->volume_valid
1335 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1336 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1339 if (source_output
->save_muted
) {
1340 entry
->muted
= pa_source_output_get_mute(source_output
);
1341 entry
->muted_valid
= TRUE
;
1343 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1346 if (source_output
->save_source
) {
1347 pa_xfree(entry
->device
);
1348 entry
->device
= pa_xstrdup(source_output
->source
->name
);
1349 entry
->device_valid
= TRUE
;
1351 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1353 if (source_output
->source
->card
) {
1354 pa_xfree(entry
->card
);
1355 entry
->card
= pa_xstrdup(source_output
->source
->card
->name
);
1356 entry
->card_valid
= TRUE
;
1365 if (entries_equal(old
, entry
)) {
1375 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1377 if (entry_write(u
, name
, entry
, TRUE
))
1381 if (created_new_entry
) {
1382 de
= dbus_entry_new(u
, name
);
1383 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1384 send_new_entry_signal(de
);
1386 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1389 send_device_updated_signal(de
, entry
);
1391 send_volume_updated_signal(de
, entry
);
1393 send_mute_updated_signal(de
, entry
);
1401 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1406 pa_assert(new_data
);
1408 pa_assert(u
->restore_device
);
1410 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1414 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1415 else if ((e
= entry_read(u
, name
))) {
1418 if (e
->device_valid
)
1419 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1421 if (!s
&& e
->card_valid
) {
1424 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1425 s
= pa_idxset_first(card
->sinks
, NULL
);
1428 /* It might happen that a stream and a sink are set up at the
1429 same time, in which case we want to make sure we don't
1430 interfere with that */
1431 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1432 if (pa_sink_input_new_data_set_sink(new_data
, s
, TRUE
))
1433 pa_log_info("Restoring device for stream %s.", name
);
1443 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1448 pa_assert(new_data
);
1450 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1452 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1455 if ((e
= entry_read(u
, name
))) {
1457 if (u
->restore_volume
&& e
->volume_valid
) {
1458 if (!new_data
->volume_writable
)
1459 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1460 else if (new_data
->volume_is_set
)
1461 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1465 pa_log_info("Restoring volume for sink input %s.", name
);
1468 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1469 pa_sink_input_new_data_set_volume(new_data
, &v
);
1471 new_data
->volume_is_absolute
= FALSE
;
1472 new_data
->save_volume
= TRUE
;
1476 if (u
->restore_muted
&& e
->muted_valid
) {
1478 if (!new_data
->muted_is_set
) {
1479 pa_log_info("Restoring mute state for sink input %s.", name
);
1480 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1481 new_data
->save_muted
= TRUE
;
1483 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1494 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1499 pa_assert(new_data
);
1501 pa_assert(u
->restore_device
);
1503 if (new_data
->direct_on_input
)
1506 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1509 if (new_data
->source
)
1510 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1511 else if ((e
= entry_read(u
, name
))) {
1512 pa_source
*s
= NULL
;
1514 if (e
->device_valid
)
1515 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1517 if (!s
&& e
->card_valid
) {
1520 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1521 s
= pa_idxset_first(card
->sources
, NULL
);
1524 /* It might happen that a stream and a sink are set up at the
1525 same time, in which case we want to make sure we don't
1526 interfere with that */
1527 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1528 pa_log_info("Restoring device for stream %s.", name
);
1529 pa_source_output_new_data_set_source(new_data
, s
, TRUE
);
1540 static pa_hook_result_t
source_output_fixate_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1545 pa_assert(new_data
);
1547 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1549 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1552 if ((e
= entry_read(u
, name
))) {
1554 if (u
->restore_volume
&& e
->volume_valid
) {
1555 if (!new_data
->volume_writable
)
1556 pa_log_debug("Not restoring volume for source output %s, because its volume can't be changed.", name
);
1557 else if (new_data
->volume_is_set
)
1558 pa_log_debug("Not restoring volume for source output %s, because already set.", name
);
1562 pa_log_info("Restoring volume for source output %s.", name
);
1565 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1566 pa_source_output_new_data_set_volume(new_data
, &v
);
1568 new_data
->volume_is_absolute
= FALSE
;
1569 new_data
->save_volume
= TRUE
;
1573 if (u
->restore_muted
&& e
->muted_valid
) {
1575 if (!new_data
->muted_is_set
) {
1576 pa_log_info("Restoring mute state for source output %s.", name
);
1577 pa_source_output_new_data_set_muted(new_data
, e
->muted
);
1578 new_data
->save_muted
= TRUE
;
1580 pa_log_debug("Not restoring mute state for source output %s, because already set.", name
);
1591 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1598 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1600 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1604 if (si
->sink
== sink
)
1610 /* Skip this if it is already in the process of being moved
1615 /* It might happen that a stream and a sink are set up at the
1616 same time, in which case we want to make sure we don't
1617 interfere with that */
1618 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1621 if (!(name
= get_name(si
->proplist
, "sink-input")))
1624 if ((e
= entry_read(u
, name
))) {
1625 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1626 pa_sink_input_move_to(si
, sink
, TRUE
);
1637 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1638 pa_source_output
*so
;
1644 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1646 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1650 if (so
->source
== source
)
1653 if (so
->save_source
)
1656 if (so
->direct_on_input
)
1659 /* Skip this if it is already in the process of being moved anyway */
1663 /* It might happen that a stream and a source are set up at the
1664 same time, in which case we want to make sure we don't
1665 interfere with that */
1666 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1669 if (!(name
= get_name(so
->proplist
, "source-output")))
1672 if ((e
= entry_read(u
, name
))) {
1673 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1674 pa_source_output_move_to(so
, source
, TRUE
);
1685 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1692 pa_assert(u
->on_rescue
&& u
->restore_device
);
1694 /* There's no point in doing anything if the core is shut down anyway */
1695 if (c
->state
== PA_CORE_SHUTDOWN
)
1698 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1705 if (!(name
= get_name(si
->proplist
, "sink-input")))
1708 if ((e
= entry_read(u
, name
))) {
1710 if (e
->device_valid
) {
1713 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1715 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1716 pa_sink_input_move_to(si
, d
, TRUE
);
1728 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1729 pa_source_output
*so
;
1735 pa_assert(u
->on_rescue
&& u
->restore_device
);
1737 /* There's no point in doing anything if the core is shut down anyway */
1738 if (c
->state
== PA_CORE_SHUTDOWN
)
1741 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1745 if (so
->direct_on_input
)
1751 if (!(name
= get_name(so
->proplist
, "source-output")))
1754 if ((e
= entry_read(u
, name
))) {
1756 if (e
->device_valid
) {
1759 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1761 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1762 pa_source_output_move_to(so
, d
, TRUE
);
1774 #define EXT_VERSION 1
1776 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
) {
1778 pa_source_output
*so
;
1785 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1789 if (!(n
= get_name(si
->proplist
, "sink-input")))
1792 if (!pa_streq(name
, n
)) {
1798 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1802 pa_log_info("Restoring volume for sink input %s.", name
);
1803 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1804 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1807 if (u
->restore_muted
&& e
->muted_valid
) {
1808 pa_log_info("Restoring mute state for sink input %s.", name
);
1809 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1812 if (u
->restore_device
) {
1813 if (!e
->device_valid
) {
1814 if (si
->save_sink
) {
1815 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1816 /* If the device is not valid we should make sure the
1817 save flag is cleared as the user may have specifically
1818 removed the sink element from the rule. */
1819 si
->save_sink
= FALSE
;
1820 /* This is cheating a bit. The sink input itself has not changed
1821 but the rules governing it's routing have, so we fire this event
1822 such that other routing modules (e.g. module-device-manager)
1823 will pick up the change and reapply their routing */
1824 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1826 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1827 pa_log_info("Restoring device for stream %s.", name
);
1828 pa_sink_input_move_to(si
, s
, TRUE
);
1833 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1837 if (!(n
= get_name(so
->proplist
, "source-output")))
1840 if (!pa_streq(name
, n
)) {
1846 if (u
->restore_volume
&& e
->volume_valid
&& so
->volume_writable
) {
1850 pa_log_info("Restoring volume for source output %s.", name
);
1851 pa_cvolume_remap(&v
, &e
->channel_map
, &so
->channel_map
);
1852 pa_source_output_set_volume(so
, &v
, TRUE
, FALSE
);
1855 if (u
->restore_muted
&& e
->muted_valid
) {
1856 pa_log_info("Restoring mute state for source output %s.", name
);
1857 pa_source_output_set_mute(so
, e
->muted
, TRUE
);
1860 if (u
->restore_device
) {
1861 if (!e
->device_valid
) {
1862 if (so
->save_source
) {
1863 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1864 /* If the device is not valid we should make sure the
1865 save flag is cleared as the user may have specifically
1866 removed the source element from the rule. */
1867 so
->save_source
= FALSE
;
1868 /* This is cheating a bit. The source output itself has not changed
1869 but the rules governing it's routing have, so we fire this event
1870 such that other routing modules (e.g. module-device-manager)
1871 will pick up the change and reapply their routing */
1872 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1874 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1875 pa_log_info("Restoring device for stream %s.", name
);
1876 pa_source_output_move_to(so
, s
, TRUE
);
1883 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1887 done
= !pa_database_first(u
->database
, &key
, NULL
);
1894 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1896 name
= pa_xstrndup(key
.data
, key
.size
);
1897 pa_datum_free(&key
);
1899 if ((e
= entry_read(u
, name
))) {
1901 pa_log("name=%s", name
);
1902 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1903 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1904 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1905 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1916 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1919 pa_tagstruct
*reply
= NULL
;
1928 if (pa_tagstruct_getu32(t
, &command
) < 0)
1931 reply
= pa_tagstruct_new(NULL
, 0);
1932 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1933 pa_tagstruct_putu32(reply
, tag
);
1936 case SUBCOMMAND_TEST
: {
1937 if (!pa_tagstruct_eof(t
))
1940 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1944 case SUBCOMMAND_READ
: {
1948 if (!pa_tagstruct_eof(t
))
1951 done
= !pa_database_first(u
->database
, &key
, NULL
);
1958 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1960 name
= pa_xstrndup(key
.data
, key
.size
);
1961 pa_datum_free(&key
);
1963 if ((e
= entry_read(u
, name
))) {
1967 pa_tagstruct_puts(reply
, name
);
1968 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1969 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1970 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1971 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1984 case SUBCOMMAND_WRITE
: {
1986 pa_bool_t apply_immediately
= FALSE
;
1988 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1989 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1992 if (mode
!= PA_UPDATE_MERGE
&&
1993 mode
!= PA_UPDATE_REPLACE
&&
1994 mode
!= PA_UPDATE_SET
)
1997 if (mode
== PA_UPDATE_SET
) {
1999 struct dbus_entry
*de
;
2002 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
2003 send_entry_removed_signal(de
);
2004 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
2007 pa_database_clear(u
->database
);
2010 while (!pa_tagstruct_eof(t
)) {
2011 const char *name
, *device
;
2013 struct entry
*entry
;
2018 entry
= entry_new();
2020 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2021 pa_tagstruct_get_channel_map(t
, &entry
->channel_map
) ||
2022 pa_tagstruct_get_cvolume(t
, &entry
->volume
) < 0 ||
2023 pa_tagstruct_gets(t
, &device
) < 0 ||
2024 pa_tagstruct_get_boolean(t
, &muted
) < 0)
2027 if (!name
|| !*name
) {
2032 entry
->volume_valid
= entry
->volume
.channels
> 0;
2034 if (entry
->volume_valid
)
2035 if (!pa_cvolume_compatible_with_channel_map(&entry
->volume
, &entry
->channel_map
)) {
2040 entry
->muted
= muted
;
2041 entry
->muted_valid
= TRUE
;
2043 entry
->device
= pa_xstrdup(device
);
2044 entry
->device_valid
= device
&& !!entry
->device
[0];
2046 if (entry
->device_valid
&& !pa_namereg_is_valid_name(entry
->device
)) {
2052 old
= entry_read(u
, name
);
2055 pa_log_debug("Client %s changes entry %s.",
2056 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
2059 if (entry_write(u
, name
, entry
, mode
== PA_UPDATE_REPLACE
)) {
2061 struct dbus_entry
*de
;
2064 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
2066 if ((old
->device_valid
!= entry
->device_valid
)
2067 || (entry
->device_valid
&& !pa_streq(entry
->device
, old
->device
)))
2068 send_device_updated_signal(de
, entry
);
2070 if ((old
->volume_valid
!= entry
->volume_valid
)
2071 || (entry
->volume_valid
&& (!pa_cvolume_equal(&entry
->volume
, &old
->volume
)
2072 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
))))
2073 send_volume_updated_signal(de
, entry
);
2075 if (!old
->muted_valid
|| (entry
->muted
!= old
->muted
))
2076 send_mute_updated_signal(de
, entry
);
2079 de
= dbus_entry_new(u
, name
);
2080 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2081 send_new_entry_signal(de
);
2085 if (apply_immediately
)
2086 entry_apply(u
, name
, entry
);
2101 case SUBCOMMAND_DELETE
:
2103 while (!pa_tagstruct_eof(t
)) {
2107 struct dbus_entry
*de
;
2110 if (pa_tagstruct_gets(t
, &name
) < 0)
2114 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
2115 send_entry_removed_signal(de
);
2116 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
2120 key
.data
= (char*) name
;
2121 key
.size
= strlen(name
);
2123 pa_database_unset(u
->database
, &key
);
2130 case SUBCOMMAND_SUBSCRIBE
: {
2134 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
2135 !pa_tagstruct_eof(t
))
2139 pa_idxset_put(u
->subscribed
, c
, NULL
);
2141 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2150 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
2156 pa_tagstruct_free(reply
);
2161 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
2166 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2170 int pa__init(pa_module
*m
) {
2171 pa_modargs
*ma
= NULL
;
2175 pa_source_output
*so
;
2177 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
2185 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2186 pa_log("Failed to parse module arguments");
2190 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2191 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2192 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2193 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2194 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2195 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2199 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2200 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2202 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2205 u
->restore_device
= restore_device
;
2206 u
->restore_volume
= restore_volume
;
2207 u
->restore_muted
= restore_muted
;
2208 u
->on_hotplug
= on_hotplug
;
2209 u
->on_rescue
= on_rescue
;
2210 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2212 u
->protocol
= pa_native_protocol_get(m
->core
);
2213 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2215 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
);
2217 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2219 if (restore_device
) {
2220 /* A little bit earlier than module-intended-roles ... */
2221 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
);
2222 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
);
2225 if (restore_device
&& on_hotplug
) {
2226 /* A little bit earlier than module-intended-roles ... */
2227 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
);
2228 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
);
2231 if (restore_device
&& on_rescue
) {
2232 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2233 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
);
2234 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
);
2237 if (restore_volume
|| restore_muted
) {
2238 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
);
2239 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
);
2242 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2245 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2246 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2251 pa_log_info("Successfully opened database file '%s'.", fname
);
2255 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2256 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2258 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2259 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2261 /* Create the initial dbus entries. */
2262 done
= !pa_database_first(u
->database
, &key
, NULL
);
2266 struct dbus_entry
*de
;
2269 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2271 name
= pa_xstrndup(key
.data
, key
.size
);
2272 pa_datum_free(&key
);
2274 /* Use entry_read() for checking that the entry is valid. */
2275 if ((e
= entry_read(u
, name
))) {
2276 de
= dbus_entry_new(u
, name
);
2277 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2287 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2288 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2290 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2291 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2293 pa_modargs_free(ma
);
2300 pa_modargs_free(ma
);
2306 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2307 struct dbus_entry
*de
= p
;
2311 dbus_entry_free(de
);
2315 void pa__done(pa_module
*m
) {
2320 if (!(u
= m
->userdata
))
2324 if (u
->dbus_protocol
) {
2325 pa_assert(u
->dbus_entries
);
2327 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2328 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2330 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2332 pa_dbus_protocol_unref(u
->dbus_protocol
);
2336 if (u
->subscription
)
2337 pa_subscription_free(u
->subscription
);
2339 if (u
->sink_input_new_hook_slot
)
2340 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2341 if (u
->sink_input_fixate_hook_slot
)
2342 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2343 if (u
->source_output_new_hook_slot
)
2344 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2345 if (u
->source_output_fixate_hook_slot
)
2346 pa_hook_slot_free(u
->source_output_fixate_hook_slot
);
2348 if (u
->sink_put_hook_slot
)
2349 pa_hook_slot_free(u
->sink_put_hook_slot
);
2350 if (u
->source_put_hook_slot
)
2351 pa_hook_slot_free(u
->source_put_hook_slot
);
2353 if (u
->sink_unlink_hook_slot
)
2354 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2355 if (u
->source_unlink_hook_slot
)
2356 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2358 if (u
->connection_unlink_hook_slot
)
2359 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2361 if (u
->save_time_event
)
2362 u
->core
->mainloop
->time_free(u
->save_time_event
);
2365 pa_database_close(u
->database
);
2368 pa_native_protocol_remove_ext(u
->protocol
, m
);
2369 pa_native_protocol_unref(u
->protocol
);
2373 pa_idxset_free(u
->subscribed
, NULL
, NULL
);