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
->muted_valid
= le
->muted_valid
;
1082 e
->muted
= le
->muted
;
1083 e
->volume_valid
= le
->volume_valid
;
1084 e
->channel_map
= le
->channel_map
;
1085 e
->volume
= le
->volume
;
1086 e
->device_valid
= le
->device_valid
;
1087 e
->device
= pa_xstrdup(le
->device
);
1088 e
->card_valid
= le
->card_valid
;
1089 e
->card
= pa_xstrdup(le
->card
);
1094 static struct entry
*entry_read(struct userdata
*u
, const char *name
) {
1096 struct entry
*e
= NULL
;
1097 pa_tagstruct
*t
= NULL
;
1098 const char *device
, *card
;
1103 key
.data
= (char*) name
;
1104 key
.size
= strlen(name
);
1108 if (!pa_database_get(u
->database
, &key
, &data
))
1111 t
= pa_tagstruct_new(data
.data
, data
.size
);
1114 if (pa_tagstruct_getu8(t
, &e
->version
) < 0 ||
1115 e
->version
> ENTRY_VERSION
||
1116 pa_tagstruct_get_boolean(t
, &e
->volume_valid
) < 0 ||
1117 pa_tagstruct_get_channel_map(t
, &e
->channel_map
) < 0 ||
1118 pa_tagstruct_get_cvolume(t
, &e
->volume
) < 0 ||
1119 pa_tagstruct_get_boolean(t
, &e
->muted_valid
) < 0 ||
1120 pa_tagstruct_get_boolean(t
, &e
->muted
) < 0 ||
1121 pa_tagstruct_get_boolean(t
, &e
->device_valid
) < 0 ||
1122 pa_tagstruct_gets(t
, &device
) < 0 ||
1123 pa_tagstruct_get_boolean(t
, &e
->card_valid
) < 0 ||
1124 pa_tagstruct_gets(t
, &card
) < 0) {
1129 e
->device
= pa_xstrdup(device
);
1130 e
->card
= pa_xstrdup(card
);
1132 if (!pa_tagstruct_eof(t
))
1135 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1136 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1140 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1141 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1145 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1146 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1150 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1151 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1155 pa_tagstruct_free(t
);
1156 pa_datum_free(&data
);
1162 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name
);
1167 pa_tagstruct_free(t
);
1169 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
1170 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name
);
1171 if ((e
= legacy_entry_read(u
, &data
))) {
1172 pa_log_debug("Success. Saving new format for key: %s", name
);
1173 if (entry_write(u
, name
, e
, TRUE
))
1175 pa_datum_free(&data
);
1178 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name
);
1181 pa_datum_free(&data
);
1185 static struct entry
* entry_copy(const struct entry
*e
) {
1191 r
->device
= pa_xstrdup(e
->device
);
1192 r
->card
= pa_xstrdup(e
->card
);
1196 static void trigger_save(struct userdata
*u
) {
1197 pa_native_connection
*c
;
1200 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1203 t
= pa_tagstruct_new(NULL
, 0);
1204 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1205 pa_tagstruct_putu32(t
, 0);
1206 pa_tagstruct_putu32(t
, u
->module
->index
);
1207 pa_tagstruct_puts(t
, u
->module
->name
);
1208 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1210 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1213 if (u
->save_time_event
)
1216 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1219 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1225 if (a
->device_valid
!= b
->device_valid
||
1226 (a
->device_valid
&& !pa_streq(a
->device
, b
->device
)))
1229 if (a
->card_valid
!= b
->card_valid
||
1230 (a
->card_valid
&& !pa_streq(a
->card
, b
->card
)))
1233 if (a
->muted_valid
!= b
->muted_valid
||
1234 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1238 if (a
->volume_valid
!= b
->volume_valid
||
1239 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1245 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1246 struct userdata
*u
= userdata
;
1247 struct entry
*entry
, *old
= NULL
;
1250 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1251 * clutter these are defined here unconditionally. */
1252 pa_bool_t created_new_entry
= TRUE
;
1253 pa_bool_t device_updated
= FALSE
;
1254 pa_bool_t volume_updated
= FALSE
;
1255 pa_bool_t mute_updated
= FALSE
;
1258 struct dbus_entry
*de
= NULL
;
1264 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1265 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1266 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1267 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1270 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1271 pa_sink_input
*sink_input
;
1273 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1276 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1279 if ((old
= entry_read(u
, name
))) {
1280 entry
= entry_copy(old
);
1281 created_new_entry
= FALSE
;
1283 entry
= entry_new();
1285 if (sink_input
->save_volume
&& pa_sink_input_is_volume_readable(sink_input
)) {
1286 pa_assert(sink_input
->volume_writable
);
1288 entry
->channel_map
= sink_input
->channel_map
;
1289 pa_sink_input_get_volume(sink_input
, &entry
->volume
, FALSE
);
1290 entry
->volume_valid
= TRUE
;
1292 volume_updated
= !created_new_entry
1293 && (!old
->volume_valid
1294 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1295 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1298 if (sink_input
->save_muted
) {
1299 entry
->muted
= pa_sink_input_get_mute(sink_input
);
1300 entry
->muted_valid
= TRUE
;
1302 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1305 if (sink_input
->save_sink
) {
1306 pa_xfree(entry
->device
);
1307 entry
->device
= pa_xstrdup(sink_input
->sink
->name
);
1308 entry
->device_valid
= TRUE
;
1310 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1311 if (sink_input
->sink
->card
) {
1312 pa_xfree(entry
->card
);
1313 entry
->card
= pa_xstrdup(sink_input
->sink
->card
->name
);
1314 entry
->card_valid
= TRUE
;
1319 pa_source_output
*source_output
;
1321 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1323 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1326 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1329 if ((old
= entry_read(u
, name
))) {
1330 entry
= entry_copy(old
);
1331 created_new_entry
= FALSE
;
1333 entry
= entry_new();
1335 if (source_output
->save_volume
&& pa_source_output_is_volume_readable(source_output
)) {
1336 pa_assert(source_output
->volume_writable
);
1338 entry
->channel_map
= source_output
->channel_map
;
1339 pa_source_output_get_volume(source_output
, &entry
->volume
, FALSE
);
1340 entry
->volume_valid
= TRUE
;
1342 volume_updated
= !created_new_entry
1343 && (!old
->volume_valid
1344 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
)
1345 || !pa_cvolume_equal(&entry
->volume
, &old
->volume
));
1348 if (source_output
->save_muted
) {
1349 entry
->muted
= pa_source_output_get_mute(source_output
);
1350 entry
->muted_valid
= TRUE
;
1352 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
->muted
!= old
->muted
);
1355 if (source_output
->save_source
) {
1356 pa_xfree(entry
->device
);
1357 entry
->device
= pa_xstrdup(source_output
->source
->name
);
1358 entry
->device_valid
= TRUE
;
1360 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
->device
, old
->device
));
1362 if (source_output
->source
->card
) {
1363 pa_xfree(entry
->card
);
1364 entry
->card
= pa_xstrdup(source_output
->source
->card
->name
);
1365 entry
->card_valid
= TRUE
;
1374 if (entries_equal(old
, entry
)) {
1384 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1386 if (entry_write(u
, name
, entry
, TRUE
))
1390 if (created_new_entry
) {
1391 de
= dbus_entry_new(u
, name
);
1392 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
1393 send_new_entry_signal(de
);
1395 pa_assert_se(de
= pa_hashmap_get(u
->dbus_entries
, name
));
1398 send_device_updated_signal(de
, entry
);
1400 send_volume_updated_signal(de
, entry
);
1402 send_mute_updated_signal(de
, entry
);
1410 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1415 pa_assert(new_data
);
1417 pa_assert(u
->restore_device
);
1419 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1423 pa_log_debug("Not restoring device for stream %s, because already set to '%s'.", name
, new_data
->sink
->name
);
1424 else if ((e
= entry_read(u
, name
))) {
1427 if (e
->device_valid
)
1428 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1430 if (!s
&& e
->card_valid
) {
1433 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1434 s
= pa_idxset_first(card
->sinks
, NULL
);
1437 /* It might happen that a stream and a sink are set up at the
1438 same time, in which case we want to make sure we don't
1439 interfere with that */
1440 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
)))
1441 if (pa_sink_input_new_data_set_sink(new_data
, s
, TRUE
))
1442 pa_log_info("Restoring device for stream %s.", name
);
1452 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1457 pa_assert(new_data
);
1459 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1461 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1464 if ((e
= entry_read(u
, name
))) {
1466 if (u
->restore_volume
&& e
->volume_valid
) {
1467 if (!new_data
->volume_writable
)
1468 pa_log_debug("Not restoring volume for sink input %s, because its volume can't be changed.", name
);
1469 else if (new_data
->volume_is_set
)
1470 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1474 pa_log_info("Restoring volume for sink input %s.", name
);
1477 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1478 pa_sink_input_new_data_set_volume(new_data
, &v
);
1480 new_data
->volume_is_absolute
= FALSE
;
1481 new_data
->save_volume
= TRUE
;
1485 if (u
->restore_muted
&& e
->muted_valid
) {
1487 if (!new_data
->muted_is_set
) {
1488 pa_log_info("Restoring mute state for sink input %s.", name
);
1489 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1490 new_data
->save_muted
= TRUE
;
1492 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1503 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1508 pa_assert(new_data
);
1510 pa_assert(u
->restore_device
);
1512 if (new_data
->direct_on_input
)
1515 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1518 if (new_data
->source
)
1519 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1520 else if ((e
= entry_read(u
, name
))) {
1521 pa_source
*s
= NULL
;
1523 if (e
->device_valid
)
1524 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1526 if (!s
&& e
->card_valid
) {
1529 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1530 s
= pa_idxset_first(card
->sources
, NULL
);
1533 /* It might happen that a stream and a sink are set up at the
1534 same time, in which case we want to make sure we don't
1535 interfere with that */
1536 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1537 pa_log_info("Restoring device for stream %s.", name
);
1538 pa_source_output_new_data_set_source(new_data
, s
, TRUE
);
1549 static pa_hook_result_t
source_output_fixate_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1554 pa_assert(new_data
);
1556 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1558 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1561 if ((e
= entry_read(u
, name
))) {
1563 if (u
->restore_volume
&& e
->volume_valid
) {
1564 if (!new_data
->volume_writable
)
1565 pa_log_debug("Not restoring volume for source output %s, because its volume can't be changed.", name
);
1566 else if (new_data
->volume_is_set
)
1567 pa_log_debug("Not restoring volume for source output %s, because already set.", name
);
1571 pa_log_info("Restoring volume for source output %s.", name
);
1574 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1575 pa_source_output_new_data_set_volume(new_data
, &v
);
1577 new_data
->volume_is_absolute
= FALSE
;
1578 new_data
->save_volume
= TRUE
;
1582 if (u
->restore_muted
&& e
->muted_valid
) {
1584 if (!new_data
->muted_is_set
) {
1585 pa_log_info("Restoring mute state for source output %s.", name
);
1586 pa_source_output_new_data_set_muted(new_data
, e
->muted
);
1587 new_data
->save_muted
= TRUE
;
1589 pa_log_debug("Not restoring mute state for source output %s, because already set.", name
);
1600 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1607 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1609 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1613 if (si
->sink
== sink
)
1619 /* Skip this if it is already in the process of being moved
1624 /* It might happen that a stream and a sink are set up at the
1625 same time, in which case we want to make sure we don't
1626 interfere with that */
1627 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1630 if (!(name
= get_name(si
->proplist
, "sink-input")))
1633 if ((e
= entry_read(u
, name
))) {
1634 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1635 pa_sink_input_move_to(si
, sink
, TRUE
);
1646 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1647 pa_source_output
*so
;
1653 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1655 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1659 if (so
->source
== source
)
1662 if (so
->save_source
)
1665 if (so
->direct_on_input
)
1668 /* Skip this if it is already in the process of being moved anyway */
1672 /* It might happen that a stream and a source are set up at the
1673 same time, in which case we want to make sure we don't
1674 interfere with that */
1675 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1678 if (!(name
= get_name(so
->proplist
, "source-output")))
1681 if ((e
= entry_read(u
, name
))) {
1682 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1683 pa_source_output_move_to(so
, source
, TRUE
);
1694 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1701 pa_assert(u
->on_rescue
&& u
->restore_device
);
1703 /* There's no point in doing anything if the core is shut down anyway */
1704 if (c
->state
== PA_CORE_SHUTDOWN
)
1707 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1714 if (!(name
= get_name(si
->proplist
, "sink-input")))
1717 if ((e
= entry_read(u
, name
))) {
1719 if (e
->device_valid
) {
1722 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1724 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1725 pa_sink_input_move_to(si
, d
, TRUE
);
1737 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1738 pa_source_output
*so
;
1744 pa_assert(u
->on_rescue
&& u
->restore_device
);
1746 /* There's no point in doing anything if the core is shut down anyway */
1747 if (c
->state
== PA_CORE_SHUTDOWN
)
1750 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1754 if (so
->direct_on_input
)
1760 if (!(name
= get_name(so
->proplist
, "source-output")))
1763 if ((e
= entry_read(u
, name
))) {
1765 if (e
->device_valid
) {
1768 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1770 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1771 pa_source_output_move_to(so
, d
, TRUE
);
1783 #define EXT_VERSION 1
1785 static void entry_apply(struct userdata
*u
, const char *name
, struct entry
*e
) {
1787 pa_source_output
*so
;
1794 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1798 if (!(n
= get_name(si
->proplist
, "sink-input")))
1801 if (!pa_streq(name
, n
)) {
1807 if (u
->restore_volume
&& e
->volume_valid
&& si
->volume_writable
) {
1811 pa_log_info("Restoring volume for sink input %s.", name
);
1812 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1813 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1816 if (u
->restore_muted
&& e
->muted_valid
) {
1817 pa_log_info("Restoring mute state for sink input %s.", name
);
1818 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1821 if (u
->restore_device
) {
1822 if (!e
->device_valid
) {
1823 if (si
->save_sink
) {
1824 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1825 /* If the device is not valid we should make sure the
1826 save flag is cleared as the user may have specifically
1827 removed the sink element from the rule. */
1828 si
->save_sink
= FALSE
;
1829 /* This is cheating a bit. The sink input itself has not changed
1830 but the rules governing it's routing have, so we fire this event
1831 such that other routing modules (e.g. module-device-manager)
1832 will pick up the change and reapply their routing */
1833 pa_subscription_post(si
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, si
->index
);
1835 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1836 pa_log_info("Restoring device for stream %s.", name
);
1837 pa_sink_input_move_to(si
, s
, TRUE
);
1842 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1846 if (!(n
= get_name(so
->proplist
, "source-output")))
1849 if (!pa_streq(name
, n
)) {
1855 if (u
->restore_volume
&& e
->volume_valid
&& so
->volume_writable
) {
1859 pa_log_info("Restoring volume for source output %s.", name
);
1860 pa_cvolume_remap(&v
, &e
->channel_map
, &so
->channel_map
);
1861 pa_source_output_set_volume(so
, &v
, TRUE
, FALSE
);
1864 if (u
->restore_muted
&& e
->muted_valid
) {
1865 pa_log_info("Restoring mute state for source output %s.", name
);
1866 pa_source_output_set_mute(so
, e
->muted
, TRUE
);
1869 if (u
->restore_device
) {
1870 if (!e
->device_valid
) {
1871 if (so
->save_source
) {
1872 pa_log_info("Ensuring device is not saved for stream %s.", name
);
1873 /* If the device is not valid we should make sure the
1874 save flag is cleared as the user may have specifically
1875 removed the source element from the rule. */
1876 so
->save_source
= FALSE
;
1877 /* This is cheating a bit. The source output itself has not changed
1878 but the rules governing it's routing have, so we fire this event
1879 such that other routing modules (e.g. module-device-manager)
1880 will pick up the change and reapply their routing */
1881 pa_subscription_post(so
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, so
->index
);
1883 } else if ((s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1884 pa_log_info("Restoring device for stream %s.", name
);
1885 pa_source_output_move_to(so
, s
, TRUE
);
1892 PA_GCC_UNUSED
static void stream_restore_dump_database(struct userdata
*u
) {
1896 done
= !pa_database_first(u
->database
, &key
, NULL
);
1903 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1905 name
= pa_xstrndup(key
.data
, key
.size
);
1906 pa_datum_free(&key
);
1908 if ((e
= entry_read(u
, name
))) {
1910 pa_log("name=%s", name
);
1911 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1912 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1913 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1914 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1925 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1928 pa_tagstruct
*reply
= NULL
;
1937 if (pa_tagstruct_getu32(t
, &command
) < 0)
1940 reply
= pa_tagstruct_new(NULL
, 0);
1941 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1942 pa_tagstruct_putu32(reply
, tag
);
1945 case SUBCOMMAND_TEST
: {
1946 if (!pa_tagstruct_eof(t
))
1949 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1953 case SUBCOMMAND_READ
: {
1957 if (!pa_tagstruct_eof(t
))
1960 done
= !pa_database_first(u
->database
, &key
, NULL
);
1967 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1969 name
= pa_xstrndup(key
.data
, key
.size
);
1970 pa_datum_free(&key
);
1972 if ((e
= entry_read(u
, name
))) {
1976 pa_tagstruct_puts(reply
, name
);
1977 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1978 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1979 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1980 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1993 case SUBCOMMAND_WRITE
: {
1995 pa_bool_t apply_immediately
= FALSE
;
1997 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1998 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
2001 if (mode
!= PA_UPDATE_MERGE
&&
2002 mode
!= PA_UPDATE_REPLACE
&&
2003 mode
!= PA_UPDATE_SET
)
2006 if (mode
== PA_UPDATE_SET
) {
2008 struct dbus_entry
*de
;
2011 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
2012 send_entry_removed_signal(de
);
2013 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
2016 pa_database_clear(u
->database
);
2019 while (!pa_tagstruct_eof(t
)) {
2020 const char *name
, *device
;
2022 struct entry
*entry
;
2027 entry
= entry_new();
2029 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2030 pa_tagstruct_get_channel_map(t
, &entry
->channel_map
) ||
2031 pa_tagstruct_get_cvolume(t
, &entry
->volume
) < 0 ||
2032 pa_tagstruct_gets(t
, &device
) < 0 ||
2033 pa_tagstruct_get_boolean(t
, &muted
) < 0)
2036 if (!name
|| !*name
) {
2041 entry
->volume_valid
= entry
->volume
.channels
> 0;
2043 if (entry
->volume_valid
)
2044 if (!pa_cvolume_compatible_with_channel_map(&entry
->volume
, &entry
->channel_map
)) {
2049 entry
->muted
= muted
;
2050 entry
->muted_valid
= TRUE
;
2052 entry
->device
= pa_xstrdup(device
);
2053 entry
->device_valid
= device
&& !!entry
->device
[0];
2055 if (entry
->device_valid
&& !pa_namereg_is_valid_name(entry
->device
)) {
2061 old
= entry_read(u
, name
);
2064 pa_log_debug("Client %s changes entry %s.",
2065 pa_strnull(pa_proplist_gets(pa_native_connection_get_client(c
)->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)),
2068 if (entry_write(u
, name
, entry
, mode
== PA_UPDATE_REPLACE
)) {
2070 struct dbus_entry
*de
;
2073 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
2075 if ((old
->device_valid
!= entry
->device_valid
)
2076 || (entry
->device_valid
&& !pa_streq(entry
->device
, old
->device
)))
2077 send_device_updated_signal(de
, entry
);
2079 if ((old
->volume_valid
!= entry
->volume_valid
)
2080 || (entry
->volume_valid
&& (!pa_cvolume_equal(&entry
->volume
, &old
->volume
)
2081 || !pa_channel_map_equal(&entry
->channel_map
, &old
->channel_map
))))
2082 send_volume_updated_signal(de
, entry
);
2084 if (!old
->muted_valid
|| (entry
->muted
!= old
->muted
))
2085 send_mute_updated_signal(de
, entry
);
2088 de
= dbus_entry_new(u
, name
);
2089 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2090 send_new_entry_signal(de
);
2094 if (apply_immediately
)
2095 entry_apply(u
, name
, entry
);
2110 case SUBCOMMAND_DELETE
:
2112 while (!pa_tagstruct_eof(t
)) {
2116 struct dbus_entry
*de
;
2119 if (pa_tagstruct_gets(t
, &name
) < 0)
2123 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
2124 send_entry_removed_signal(de
);
2125 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
2129 key
.data
= (char*) name
;
2130 key
.size
= strlen(name
);
2132 pa_database_unset(u
->database
, &key
);
2139 case SUBCOMMAND_SUBSCRIBE
: {
2143 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
2144 !pa_tagstruct_eof(t
))
2148 pa_idxset_put(u
->subscribed
, c
, NULL
);
2150 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2159 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
2165 pa_tagstruct_free(reply
);
2170 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
2175 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
2179 int pa__init(pa_module
*m
) {
2180 pa_modargs
*ma
= NULL
;
2184 pa_source_output
*so
;
2186 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
2194 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2195 pa_log("Failed to parse module arguments");
2199 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2200 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2201 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2202 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2203 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2204 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2208 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2209 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2211 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2214 u
->restore_device
= restore_device
;
2215 u
->restore_volume
= restore_volume
;
2216 u
->restore_muted
= restore_muted
;
2217 u
->on_hotplug
= on_hotplug
;
2218 u
->on_rescue
= on_rescue
;
2219 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2221 u
->protocol
= pa_native_protocol_get(m
->core
);
2222 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2224 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
);
2226 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2228 if (restore_device
) {
2229 /* A little bit earlier than module-intended-roles ... */
2230 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
);
2231 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
);
2234 if (restore_device
&& on_hotplug
) {
2235 /* A little bit earlier than module-intended-roles ... */
2236 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
);
2237 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
);
2240 if (restore_device
&& on_rescue
) {
2241 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2242 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
);
2243 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
);
2246 if (restore_volume
|| restore_muted
) {
2247 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
);
2248 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
);
2251 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2254 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2255 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2260 pa_log_info("Successfully opened database file '%s'.", fname
);
2264 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2265 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2267 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2268 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2270 /* Create the initial dbus entries. */
2271 done
= !pa_database_first(u
->database
, &key
, NULL
);
2275 struct dbus_entry
*de
;
2278 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2280 name
= pa_xstrndup(key
.data
, key
.size
);
2281 pa_datum_free(&key
);
2283 /* Use entry_read() for checking that the entry is valid. */
2284 if ((e
= entry_read(u
, name
))) {
2285 de
= dbus_entry_new(u
, name
);
2286 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) == 0);
2296 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2297 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2299 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2300 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2302 pa_modargs_free(ma
);
2309 pa_modargs_free(ma
);
2315 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2316 struct dbus_entry
*de
= p
;
2320 dbus_entry_free(de
);
2324 void pa__done(pa_module
*m
) {
2329 if (!(u
= m
->userdata
))
2333 if (u
->dbus_protocol
) {
2334 pa_assert(u
->dbus_entries
);
2336 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2337 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2339 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2341 pa_dbus_protocol_unref(u
->dbus_protocol
);
2345 if (u
->subscription
)
2346 pa_subscription_free(u
->subscription
);
2348 if (u
->sink_input_new_hook_slot
)
2349 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2350 if (u
->sink_input_fixate_hook_slot
)
2351 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2352 if (u
->source_output_new_hook_slot
)
2353 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2354 if (u
->source_output_fixate_hook_slot
)
2355 pa_hook_slot_free(u
->source_output_fixate_hook_slot
);
2357 if (u
->sink_put_hook_slot
)
2358 pa_hook_slot_free(u
->sink_put_hook_slot
);
2359 if (u
->source_put_hook_slot
)
2360 pa_hook_slot_free(u
->source_put_hook_slot
);
2362 if (u
->sink_unlink_hook_slot
)
2363 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2364 if (u
->source_unlink_hook_slot
)
2365 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2367 if (u
->connection_unlink_hook_slot
)
2368 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2370 if (u
->save_time_event
)
2371 u
->core
->mainloop
->time_free(u
->save_time_event
);
2374 pa_database_close(u
->database
);
2377 pa_native_protocol_remove_ext(u
->protocol
, m
);
2378 pa_native_protocol_unref(u
->protocol
);
2382 pa_idxset_free(u
->subscribed
, NULL
, NULL
);