2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
5 Copyright 2009 Tanu Kaskinen
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <sys/types.h>
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/util.h>
39 #include <pulse/rtclock.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/modargs.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/core-subscribe.h>
47 #include <pulsecore/sink-input.h>
48 #include <pulsecore/source-output.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/protocol-native.h>
51 #include <pulsecore/pstream.h>
52 #include <pulsecore/pstream-util.h>
53 #include <pulsecore/database.h>
56 #include <pulsecore/dbus-util.h>
57 #include <pulsecore/protocol-dbus.h>
60 #include "module-stream-restore-symdef.h"
62 PA_MODULE_AUTHOR("Lennart Poettering");
63 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute/device state of streams");
64 PA_MODULE_VERSION(PACKAGE_VERSION
);
65 PA_MODULE_LOAD_ONCE(TRUE
);
67 "restore_device=<Save/restore sinks/sources?> "
68 "restore_volume=<Save/restore volumes?> "
69 "restore_muted=<Save/restore muted states?> "
70 "on_hotplug=<When new device becomes available, recheck streams?> "
71 "on_rescue=<When device becomes unavailable, recheck streams?>");
73 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
74 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
76 static const char* const valid_modargs
[] = {
88 pa_subscription
*subscription
;
90 *sink_input_new_hook_slot
,
91 *sink_input_fixate_hook_slot
,
92 *source_output_new_hook_slot
,
94 *source_put_hook_slot
,
95 *sink_unlink_hook_slot
,
96 *source_unlink_hook_slot
,
97 *connection_unlink_hook_slot
;
98 pa_time_event
*save_time_event
;
99 pa_database
* database
;
101 pa_bool_t restore_device
:1;
102 pa_bool_t restore_volume
:1;
103 pa_bool_t restore_muted
:1;
104 pa_bool_t on_hotplug
:1;
105 pa_bool_t on_rescue
:1;
107 pa_native_protocol
*protocol
;
108 pa_idxset
*subscribed
;
111 pa_dbus_protocol
*dbus_protocol
;
112 pa_hashmap
*dbus_entries
;
113 uint32_t next_index
; /* For generating object paths for entries. */
117 #define ENTRY_VERSION 3
121 pa_bool_t muted_valid
:1, volume_valid
:1, device_valid
:1, card_valid
:1;
123 pa_channel_map channel_map
;
125 char device
[PA_NAME_MAX
];
126 char card
[PA_NAME_MAX
];
134 SUBCOMMAND_SUBSCRIBE
,
138 static struct entry
*read_entry(struct userdata
*u
, const char *name
);
139 static void apply_entry(struct userdata
*u
, const char *name
, struct entry
*e
);
140 static void trigger_save(struct userdata
*u
);
144 #define OBJECT_PATH "/org/pulseaudio/stream_restore1"
145 #define ENTRY_OBJECT_NAME "entry"
146 #define INTERFACE_STREAM_RESTORE "org.PulseAudio.Ext.StreamRestore1"
147 #define INTERFACE_ENTRY INTERFACE_STREAM_RESTORE ".RestoreEntry"
149 #define DBUS_INTERFACE_REVISION 0
152 struct userdata
*userdata
;
159 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
160 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
162 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
164 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
165 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
167 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
168 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
169 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
170 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
171 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
172 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
173 static void handle_entry_get_is_muted(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
174 static void handle_entry_set_is_muted(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
176 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
178 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
180 enum property_handler_index
{
181 PROPERTY_HANDLER_INTERFACE_REVISION
,
182 PROPERTY_HANDLER_ENTRIES
,
186 enum entry_property_handler_index
{
187 ENTRY_PROPERTY_HANDLER_INDEX
,
188 ENTRY_PROPERTY_HANDLER_NAME
,
189 ENTRY_PROPERTY_HANDLER_DEVICE
,
190 ENTRY_PROPERTY_HANDLER_VOLUME
,
191 ENTRY_PROPERTY_HANDLER_IS_MUTED
,
192 ENTRY_PROPERTY_HANDLER_MAX
195 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
196 [PROPERTY_HANDLER_INTERFACE_REVISION
] = { .property_name
= "InterfaceRevision", .type
= "u", .get_cb
= handle_get_interface_revision
, .set_cb
= NULL
},
197 [PROPERTY_HANDLER_ENTRIES
] = { .property_name
= "Entries", .type
= "ao", .get_cb
= handle_get_entries
, .set_cb
= NULL
}
200 static pa_dbus_property_handler entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MAX
] = {
201 [ENTRY_PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_entry_get_index
, .set_cb
= NULL
},
202 [ENTRY_PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_entry_get_name
, .set_cb
= NULL
},
203 [ENTRY_PROPERTY_HANDLER_DEVICE
] = { .property_name
= "Device", .type
= "s", .get_cb
= handle_entry_get_device
, .set_cb
= handle_entry_set_device
},
204 [ENTRY_PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "a(uu)", .get_cb
= handle_entry_get_volume
, .set_cb
= handle_entry_set_volume
},
205 [ENTRY_PROPERTY_HANDLER_IS_MUTED
] = { .property_name
= "IsMuted", .type
= "b", .get_cb
= handle_entry_get_is_muted
, .set_cb
= handle_entry_set_is_muted
}
208 enum method_handler_index
{
209 METHOD_HANDLER_ADD_ENTRY
,
210 METHOD_HANDLER_GET_ENTRY_BY_NAME
,
214 enum entry_method_handler_index
{
215 ENTRY_METHOD_HANDLER_REMOVE
,
216 ENTRY_METHOD_HANDLER_MAX
219 static pa_dbus_arg_info add_entry_args
[] = { { "name", "s", "in" },
220 { "device", "s", "in" },
221 { "volume", "a(uu)", "in" },
222 { "is_muted", "b", "in" },
223 { "entry", "o", "out" } };
224 static pa_dbus_arg_info get_entry_by_name_args
[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
226 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
227 [METHOD_HANDLER_ADD_ENTRY
] = {
228 .method_name
= "AddEntry",
229 .arguments
= add_entry_args
,
230 .n_arguments
= sizeof(add_entry_args
) / sizeof(pa_dbus_arg_info
),
231 .receive_cb
= handle_add_entry
},
232 [METHOD_HANDLER_GET_ENTRY_BY_NAME
] = {
233 .method_name
= "GetEntryByName",
234 .arguments
= get_entry_by_name_args
,
235 .n_arguments
= sizeof(get_entry_by_name_args
) / sizeof(pa_dbus_arg_info
),
236 .receive_cb
= handle_get_entry_by_name
}
239 static pa_dbus_method_handler entry_method_handlers
[ENTRY_METHOD_HANDLER_MAX
] = {
240 [ENTRY_METHOD_HANDLER_REMOVE
] = {
241 .method_name
= "Remove",
244 .receive_cb
= handle_entry_remove
}
249 SIGNAL_ENTRY_REMOVED
,
253 enum entry_signal_index
{
254 ENTRY_SIGNAL_DEVICE_UPDATED
,
255 ENTRY_SIGNAL_VOLUME_UPDATED
,
256 ENTRY_SIGNAL_MUTE_UPDATED
,
260 static pa_dbus_arg_info new_entry_args
[] = { { "entry", "o", NULL
} };
261 static pa_dbus_arg_info entry_removed_args
[] = { { "entry", "o", NULL
} };
263 static pa_dbus_arg_info entry_device_updated_args
[] = { { "device", "s", NULL
} };
264 static pa_dbus_arg_info entry_volume_updated_args
[] = { { "volume", "a(uu)", NULL
} };
265 static pa_dbus_arg_info entry_mute_updated_args
[] = { { "muted", "b", NULL
} };
267 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
268 [SIGNAL_NEW_ENTRY
] = { .name
= "NewEntry", .arguments
= new_entry_args
, .n_arguments
= 1 },
269 [SIGNAL_ENTRY_REMOVED
] = { .name
= "EntryRemoved", .arguments
= entry_removed_args
, .n_arguments
= 1 }
272 static pa_dbus_signal_info entry_signals
[ENTRY_SIGNAL_MAX
] = {
273 [ENTRY_SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= entry_device_updated_args
, .n_arguments
= 1 },
274 [ENTRY_SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= entry_volume_updated_args
, .n_arguments
= 1 },
275 [ENTRY_SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= entry_mute_updated_args
, .n_arguments
= 1 }
278 static pa_dbus_interface_info stream_restore_interface_info
= {
279 .name
= INTERFACE_STREAM_RESTORE
,
280 .method_handlers
= method_handlers
,
281 .n_method_handlers
= METHOD_HANDLER_MAX
,
282 .property_handlers
= property_handlers
,
283 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
284 .get_all_properties_cb
= handle_get_all
,
286 .n_signals
= SIGNAL_MAX
289 static pa_dbus_interface_info entry_interface_info
= {
290 .name
= INTERFACE_ENTRY
,
291 .method_handlers
= entry_method_handlers
,
292 .n_method_handlers
= ENTRY_METHOD_HANDLER_MAX
,
293 .property_handlers
= entry_property_handlers
,
294 .n_property_handlers
= ENTRY_PROPERTY_HANDLER_MAX
,
295 .get_all_properties_cb
= handle_entry_get_all
,
296 .signals
= entry_signals
,
297 .n_signals
= ENTRY_SIGNAL_MAX
300 static struct dbus_entry
*dbus_entry_new(struct userdata
*u
, const char *entry_name
) {
301 struct dbus_entry
*de
;
304 pa_assert(entry_name
);
305 pa_assert(*entry_name
);
307 de
= pa_xnew(struct dbus_entry
, 1);
309 de
->entry_name
= pa_xstrdup(entry_name
);
310 de
->index
= u
->next_index
++;
311 de
->object_path
= pa_sprintf_malloc("%s/%s%u", OBJECT_PATH
, ENTRY_OBJECT_NAME
, de
->index
);
313 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, de
->object_path
, &entry_interface_info
, u
) >= 0);
318 static void dbus_entry_free(struct dbus_entry
*de
) {
321 pa_assert_se(pa_dbus_protocol_remove_interface(de
->userdata
->dbus_protocol
, de
->object_path
, entry_interface_info
.name
) >= 0);
323 pa_xfree(de
->entry_name
);
324 pa_xfree(de
->object_path
);
327 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
328 * are a channel position and a volume value, respectively. The result is
329 * stored in the map and vol arguments. If the volume can't be read from the
330 * iterator, an error reply is sent and a negative number is returned. In case
331 * of a failure we make no guarantees about the state of map and vol. In case
332 * of an empty array the channels field of both map and vol are set to 0. */
333 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
334 DBusMessageIter array_iter
;
335 DBusMessageIter struct_iter
;
344 pa_channel_map_init(map
);
345 pa_cvolume_init(vol
);
350 arg_type
= dbus_message_iter_get_arg_type(iter
);
351 if (arg_type
!= DBUS_TYPE_ARRAY
) {
352 if (arg_type
== DBUS_TYPE_INVALID
)
353 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too few arguments. An array was expected.");
355 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong argument type: '%c'. An array was expected.", (char) arg_type
);
359 arg_type
= dbus_message_iter_get_element_type(iter
);
360 if (arg_type
!= DBUS_TYPE_STRUCT
) {
361 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong array element type: '%c'. A struct was expected.", (char) arg_type
);
365 dbus_message_iter_recurse(iter
, &array_iter
);
367 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
368 dbus_uint32_t chan_pos
;
369 dbus_uint32_t chan_vol
;
371 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
373 arg_type
= dbus_message_iter_get_arg_type(&struct_iter
);
374 if (arg_type
!= DBUS_TYPE_UINT32
) {
375 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong channel position type: '%c'. An unsigned 32-bit integer was expected.", (char) arg_type
);
379 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
380 dbus_message_iter_next(&struct_iter
);
382 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
383 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
387 arg_type
= dbus_message_iter_get_arg_type(&struct_iter
);
388 if (arg_type
!= DBUS_TYPE_UINT32
) {
389 if (arg_type
== DBUS_TYPE_INVALID
)
390 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Channel volume missing.");
392 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong volume value type: '%c'. An unsigned 32-bit integer was expected.", (char) arg_type
);
396 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
398 if (chan_vol
> PA_VOLUME_MAX
) {
399 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
403 if (map
->channels
< PA_CHANNELS_MAX
) {
404 map
->map
[map
->channels
] = chan_pos
;
405 vol
->values
[map
->channels
] = chan_vol
;
410 dbus_message_iter_next(&array_iter
);
413 if (map
->channels
> PA_CHANNELS_MAX
) {
414 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
418 dbus_message_iter_next(iter
);
423 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
424 DBusMessageIter array_iter
;
425 DBusMessageIter struct_iter
;
431 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
433 if (!e
->volume_valid
) {
434 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
438 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
439 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
441 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
442 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
444 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
447 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
450 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
451 DBusMessageIter variant_iter
;
456 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
458 append_volume(&variant_iter
, e
);
460 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
463 static void send_new_entry_signal(struct dbus_entry
*entry
) {
468 pa_assert_se(signal
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
469 pa_assert_se(dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
470 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal
);
471 dbus_message_unref(signal
);
474 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
479 pa_assert_se(signal
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
480 pa_assert_se(dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
481 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal
);
482 dbus_message_unref(signal
);
485 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
492 device
= e
->device_valid
? e
->device
: "";
494 pa_assert_se(signal
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
495 pa_assert_se(dbus_message_append_args(signal
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
496 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal
);
497 dbus_message_unref(signal
);
500 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
502 DBusMessageIter msg_iter
;
507 pa_assert_se(signal
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
508 dbus_message_iter_init_append(signal
, &msg_iter
);
509 append_volume(&msg_iter
, e
);
510 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal
);
511 dbus_message_unref(signal
);
514 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
521 pa_assert(e
->muted_valid
);
525 pa_assert_se(signal
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
526 pa_assert_se(dbus_message_append_args(signal
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
527 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal
);
528 dbus_message_unref(signal
);
531 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
532 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
537 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
540 /* The caller frees the array, but not the strings. */
541 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
542 const char **entries
;
545 struct dbus_entry
*de
;
550 *n
= pa_hashmap_size(u
->dbus_entries
);
555 entries
= pa_xnew(const char *, *n
);
557 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
)
558 entries
[i
++] = de
->object_path
;
563 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
564 struct userdata
*u
= userdata
;
565 const char **entries
;
572 entries
= get_entries(u
, &n
);
574 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
579 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
580 struct userdata
*u
= userdata
;
581 DBusMessage
*reply
= NULL
;
582 DBusMessageIter msg_iter
;
583 DBusMessageIter dict_iter
;
584 dbus_uint32_t interface_revision
;
585 const char **entries
;
592 interface_revision
= DBUS_INTERFACE_REVISION
;
593 entries
= get_entries(u
, &n_entries
);
595 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
597 dbus_message_iter_init_append(reply
, &msg_iter
);
598 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
600 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
601 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
603 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
605 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
607 dbus_message_unref(reply
);
612 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
613 struct userdata
*u
= userdata
;
614 DBusMessageIter msg_iter
;
620 dbus_bool_t apply_immediately
;
623 struct dbus_entry
*dbus_entry
;
630 if (!dbus_message_iter_init(msg
, &msg_iter
)) {
631 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too few arguments.");
635 if (pa_dbus_get_basic_arg(conn
, msg
, &msg_iter
, DBUS_TYPE_STRING
, &name
) < 0)
638 if (pa_dbus_get_basic_arg(conn
, msg
, &msg_iter
, DBUS_TYPE_STRING
, &device
) < 0)
641 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
644 if (pa_dbus_get_basic_arg(conn
, msg
, &msg_iter
, DBUS_TYPE_BOOLEAN
, &muted
) < 0)
647 if (pa_dbus_get_basic_arg(conn
, msg
, &msg_iter
, DBUS_TYPE_BOOLEAN
, &apply_immediately
) < 0)
651 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
655 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
656 pa_bool_t mute_updated
= FALSE
;
657 pa_bool_t volume_updated
= FALSE
;
658 pa_bool_t device_updated
= FALSE
;
660 pa_assert_se(e
= read_entry(u
, name
));
661 mute_updated
= e
->muted
!= muted
;
663 e
->muted_valid
= TRUE
;
665 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
667 e
->channel_map
= map
;
668 e
->volume_valid
= !!map
.channels
;
670 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
671 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
672 e
->device_valid
= !!device
[0];
675 send_mute_updated_signal(dbus_entry
, e
);
677 send_volume_updated_signal(dbus_entry
, e
);
679 send_device_updated_signal(dbus_entry
, e
);
682 dbus_entry
= dbus_entry_new(u
, name
);
683 pa_assert(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) >= 0);
685 e
->muted_valid
= TRUE
;
686 e
->volume_valid
= !!map
.channels
;
687 e
->device_valid
= !!device
[0];
690 e
->channel_map
= map
;
691 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
693 send_new_entry_signal(dbus_entry
);
696 key
.data
= (char *) name
;
697 key
.size
= strlen(name
);
700 value
.size
= sizeof(struct entry
);
702 pa_assert_se(pa_database_set(u
->database
, &key
, &value
, TRUE
) == 0);
703 if (apply_immediately
)
704 apply_entry(u
, name
, e
);
708 pa_dbus_send_empty_reply(conn
, msg
);
713 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
714 struct userdata
*u
= userdata
;
716 struct dbus_entry
*de
;
723 dbus_error_init(&error
);
725 if (!dbus_message_get_args(msg
, &error
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
)) {
726 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
727 dbus_error_free(&error
);
731 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
732 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
736 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
739 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
740 struct dbus_entry
*de
= userdata
;
746 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
749 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
750 struct dbus_entry
*de
= userdata
;
756 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
759 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
760 struct dbus_entry
*de
= userdata
;
768 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
770 device
= e
->device_valid
? e
->device
: "";
772 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
777 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
778 struct dbus_entry
*de
= userdata
;
787 if (pa_dbus_get_basic_set_property_arg(conn
, msg
, DBUS_TYPE_STRING
, &device
) < 0)
790 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
792 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
798 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
799 e
->device_valid
= !!device
[0];
801 key
.data
= de
->entry_name
;
802 key
.size
= strlen(de
->entry_name
);
804 value
.size
= sizeof(struct entry
);
805 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
807 send_device_updated_signal(de
, e
);
808 trigger_save(de
->userdata
);
811 pa_dbus_send_empty_reply(conn
, msg
);
816 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
817 struct dbus_entry
*de
= userdata
;
819 DBusMessageIter msg_iter
;
826 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
828 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
830 dbus_message_iter_init_append(reply
, &msg_iter
);
831 append_volume_variant(&msg_iter
, e
);
833 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
838 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
839 struct dbus_entry
*de
= userdata
;
840 DBusMessageIter msg_iter
;
850 /* Skip the interface and property name arguments. */
851 if (!dbus_message_iter_init(msg
, &msg_iter
) || !dbus_message_iter_next(&msg_iter
) || !dbus_message_iter_next(&msg_iter
)) {
852 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too few arguments.");
856 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
859 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
861 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
868 e
->channel_map
= map
;
869 e
->volume_valid
= !!map
.channels
;
871 key
.data
= de
->entry_name
;
872 key
.size
= strlen(de
->entry_name
);
874 value
.size
= sizeof(struct entry
);
875 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
877 send_volume_updated_signal(de
, e
);
878 trigger_save(de
->userdata
);
881 pa_dbus_send_empty_reply(conn
, msg
);
886 static void handle_entry_get_is_muted(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
887 struct dbus_entry
*de
= userdata
;
895 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
897 muted
= e
->muted_valid
? e
->muted
: FALSE
;
899 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &muted
);
904 static void handle_entry_set_is_muted(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
905 struct dbus_entry
*de
= userdata
;
914 if (pa_dbus_get_basic_set_property_arg(conn
, msg
, DBUS_TYPE_BOOLEAN
, &muted
) < 0)
917 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
919 updated
= !e
->muted_valid
|| e
->muted
!= muted
;
926 e
->muted_valid
= TRUE
;
928 key
.data
= de
->entry_name
;
929 key
.size
= strlen(de
->entry_name
);
931 value
.size
= sizeof(struct entry
);
932 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
934 send_mute_updated_signal(de
, e
);
935 trigger_save(de
->userdata
);
938 pa_dbus_send_empty_reply(conn
, msg
);
943 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
944 struct dbus_entry
*de
= userdata
;
946 DBusMessage
*reply
= NULL
;
947 DBusMessageIter msg_iter
;
948 DBusMessageIter dict_iter
;
949 DBusMessageIter dict_entry_iter
;
957 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
959 device
= e
->device_valid
? e
->device
: "";
960 muted
= e
->muted_valid
? e
->muted
: FALSE
;
962 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
964 dbus_message_iter_init_append(reply
, &msg_iter
);
965 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
967 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
968 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
969 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
971 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
973 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
974 append_volume_variant(&dict_entry_iter
, e
);
976 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
978 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_IS_MUTED
].property_name
, DBUS_TYPE_BOOLEAN
, &muted
);
980 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
982 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
984 dbus_message_unref(reply
);
989 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
990 struct dbus_entry
*de
= userdata
;
997 key
.data
= de
->entry_name
;
998 key
.size
= strlen(de
->entry_name
);
1000 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
1002 send_entry_removed_signal(de
);
1003 trigger_save(de
->userdata
);
1005 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
1006 dbus_entry_free(de
);
1008 pa_dbus_send_empty_reply(conn
, msg
);
1011 #endif /* HAVE_DBUS */
1013 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
1014 struct userdata
*u
= userdata
;
1020 pa_assert(e
== u
->save_time_event
);
1021 u
->core
->mainloop
->time_free(u
->save_time_event
);
1022 u
->save_time_event
= NULL
;
1024 pa_database_sync(u
->database
);
1025 pa_log_info("Synced.");
1028 static char *get_name(pa_proplist
*p
, const char *prefix
) {
1035 if ((r
= pa_proplist_gets(p
, IDENTIFICATION_PROPERTY
)))
1036 return pa_xstrdup(r
);
1038 if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_ROLE
)))
1039 t
= pa_sprintf_malloc("%s-by-media-role:%s", prefix
, r
);
1040 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_ID
)))
1041 t
= pa_sprintf_malloc("%s-by-application-id:%s", prefix
, r
);
1042 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_NAME
)))
1043 t
= pa_sprintf_malloc("%s-by-application-name:%s", prefix
, r
);
1044 else if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
)))
1045 t
= pa_sprintf_malloc("%s-by-media-name:%s", prefix
, r
);
1047 t
= pa_sprintf_malloc("%s-fallback:%s", prefix
, r
);
1049 pa_proplist_sets(p
, IDENTIFICATION_PROPERTY
, t
);
1053 static struct entry
*read_entry(struct userdata
*u
, const char *name
) {
1060 key
.data
= (char*) name
;
1061 key
.size
= strlen(name
);
1065 if (!pa_database_get(u
->database
, &key
, &data
))
1068 if (data
.size
!= sizeof(struct entry
)) {
1069 /* This is probably just a database upgrade, hence let's not
1070 * consider this more than a debug message */
1071 pa_log_debug("Database contains entry for stream %s of wrong size %lu != %lu. Probably due to uprade, ignoring.", name
, (unsigned long) data
.size
, (unsigned long) sizeof(struct entry
));
1075 e
= (struct entry
*) data
.data
;
1077 if (e
->version
!= ENTRY_VERSION
) {
1078 pa_log_debug("Version of database entry for stream %s doesn't match our version. Probably due to upgrade, ignoring.", name
);
1082 if (!memchr(e
->device
, 0, sizeof(e
->device
))) {
1083 pa_log_warn("Database contains entry for stream %s with missing NUL byte in device name", name
);
1087 if (!memchr(e
->card
, 0, sizeof(e
->card
))) {
1088 pa_log_warn("Database contains entry for stream %s with missing NUL byte in card name", name
);
1092 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1093 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1097 if (e
->card_valid
&& !pa_namereg_is_valid_name(e
->card
)) {
1098 pa_log_warn("Invalid card name stored in database for stream %s", name
);
1102 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1103 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1107 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1108 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1116 pa_datum_free(&data
);
1120 static void trigger_save(struct userdata
*u
) {
1121 pa_native_connection
*c
;
1124 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1127 t
= pa_tagstruct_new(NULL
, 0);
1128 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1129 pa_tagstruct_putu32(t
, 0);
1130 pa_tagstruct_putu32(t
, u
->module
->index
);
1131 pa_tagstruct_puts(t
, u
->module
->name
);
1132 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1134 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1137 if (u
->save_time_event
)
1140 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1143 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1149 if (a
->device_valid
!= b
->device_valid
||
1150 (a
->device_valid
&& strncmp(a
->device
, b
->device
, sizeof(a
->device
))))
1153 if (a
->card_valid
!= b
->card_valid
||
1154 (a
->card_valid
&& strncmp(a
->card
, b
->card
, sizeof(a
->card
))))
1157 if (a
->muted_valid
!= b
->muted_valid
||
1158 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1162 if (a
->volume_valid
!= b
->volume_valid
||
1163 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1169 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1170 struct userdata
*u
= userdata
;
1171 struct entry entry
, *old
;
1175 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1176 * clutter these are defined here unconditionally. */
1177 pa_bool_t created_new_entry
= TRUE
;
1178 pa_bool_t device_updated
= FALSE
;
1179 pa_bool_t volume_updated
= FALSE
;
1180 pa_bool_t mute_updated
= FALSE
;
1183 struct dbus_entry
*de
= NULL
;
1189 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1190 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1191 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1192 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1196 entry
.version
= ENTRY_VERSION
;
1198 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1199 pa_sink_input
*sink_input
;
1201 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1204 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1207 if ((old
= read_entry(u
, name
))) {
1209 created_new_entry
= FALSE
;
1212 if (sink_input
->save_volume
) {
1213 entry
.channel_map
= sink_input
->channel_map
;
1214 pa_sink_input_get_volume(sink_input
, &entry
.volume
, FALSE
);
1215 entry
.volume_valid
= TRUE
;
1217 volume_updated
= !created_new_entry
1218 && (!old
->volume_valid
1219 || !pa_channel_map_equal(&entry
.channel_map
, &old
->channel_map
)
1220 || !pa_cvolume_equal(&entry
.volume
, &old
->volume
));
1223 if (sink_input
->save_muted
) {
1224 entry
.muted
= pa_sink_input_get_mute(sink_input
);
1225 entry
.muted_valid
= TRUE
;
1227 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
.muted
!= old
->muted
);
1230 if (sink_input
->save_sink
) {
1231 pa_strlcpy(entry
.device
, sink_input
->sink
->name
, sizeof(entry
.device
));
1232 entry
.device_valid
= TRUE
;
1234 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
.device
, old
->device
));
1235 if (sink_input
->sink
->card
) {
1236 pa_strlcpy(entry
.card
, sink_input
->sink
->card
->name
, sizeof(entry
.card
));
1237 entry
.card_valid
= TRUE
;
1242 pa_source_output
*source_output
;
1244 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1246 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1249 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1252 if ((old
= read_entry(u
, name
))) {
1254 created_new_entry
= FALSE
;
1257 if (source_output
->save_source
) {
1258 pa_strlcpy(entry
.device
, source_output
->source
->name
, sizeof(entry
.device
));
1259 entry
.device_valid
= source_output
->save_source
;
1261 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
.device
, old
->device
));
1263 if (source_output
->source
->card
) {
1264 pa_strlcpy(entry
.card
, source_output
->source
->card
->name
, sizeof(entry
.card
));
1265 entry
.card_valid
= TRUE
;
1272 if (entries_equal(old
, &entry
)) {
1282 key
.size
= strlen(name
);
1285 data
.size
= sizeof(entry
);
1287 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1289 pa_database_set(u
->database
, &key
, &data
, TRUE
);
1292 if (created_new_entry
) {
1293 de
= dbus_entry_new(u
, name
);
1294 pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
);
1295 send_new_entry_signal(de
);
1297 pa_assert((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1300 send_device_updated_signal(de
, &entry
);
1302 send_volume_updated_signal(de
, &entry
);
1304 send_mute_updated_signal(de
, &entry
);
1313 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1318 pa_assert(new_data
);
1320 pa_assert(u
->restore_device
);
1322 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1326 pa_log_debug("Not restoring device for stream %s, because already set.", name
);
1327 else if ((e
= read_entry(u
, name
))) {
1330 if (e
->device_valid
)
1331 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
);
1333 if (!s
&& e
->card_valid
) {
1336 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1337 s
= pa_idxset_first(card
->sinks
, NULL
);
1340 /* It might happen that a stream and a sink are set up at the
1341 same time, in which case we want to make sure we don't
1342 interfere with that */
1343 if (s
&& PA_SINK_IS_LINKED(pa_sink_get_state(s
))) {
1344 pa_log_info("Restoring device for stream %s.", name
);
1346 new_data
->save_sink
= TRUE
;
1357 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1362 pa_assert(new_data
);
1364 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1366 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1369 if ((e
= read_entry(u
, name
))) {
1371 if (u
->restore_volume
&& e
->volume_valid
) {
1373 if (!new_data
->volume_is_set
) {
1376 pa_log_info("Restoring volume for sink input %s.", name
);
1379 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1380 pa_sink_input_new_data_set_volume(new_data
, &v
);
1382 new_data
->volume_is_absolute
= FALSE
;
1383 new_data
->save_volume
= TRUE
;
1385 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1388 if (u
->restore_muted
&& e
->muted_valid
) {
1390 if (!new_data
->muted_is_set
) {
1391 pa_log_info("Restoring mute state for sink input %s.", name
);
1392 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1393 new_data
->save_muted
= TRUE
;
1395 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1406 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1411 pa_assert(new_data
);
1413 pa_assert(u
->restore_device
);
1415 if (new_data
->direct_on_input
)
1418 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1421 if (new_data
->source
)
1422 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1423 else if ((e
= read_entry(u
, name
))) {
1424 pa_source
*s
= NULL
;
1426 if (e
->device_valid
)
1427 s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
);
1429 if (!s
&& e
->card_valid
) {
1432 if ((card
= pa_namereg_get(c
, e
->card
, PA_NAMEREG_CARD
)))
1433 s
= pa_idxset_first(card
->sources
, NULL
);
1436 /* It might happen that a stream and a sink are set up at the
1437 same time, in which case we want to make sure we don't
1438 interfere with that */
1439 if (s
&& PA_SOURCE_IS_LINKED(pa_source_get_state(s
))) {
1440 pa_log_info("Restoring device for stream %s.", name
);
1441 new_data
->source
= s
;
1442 new_data
->save_source
= TRUE
;
1453 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1460 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1462 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1466 if (si
->sink
== sink
)
1472 /* Skip this if it is already in the process of being moved
1477 /* It might happen that a stream and a sink are set up at the
1478 same time, in which case we want to make sure we don't
1479 interfere with that */
1480 if (!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(si
)))
1483 if (!(name
= get_name(si
->proplist
, "sink-input")))
1486 if ((e
= read_entry(u
, name
))) {
1487 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1488 pa_sink_input_move_to(si
, sink
, TRUE
);
1499 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1500 pa_source_output
*so
;
1506 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1508 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1512 if (so
->source
== source
)
1515 if (so
->save_source
)
1518 if (so
->direct_on_input
)
1521 /* Skip this if it is already in the process of being moved anyway */
1525 /* It might happen that a stream and a sink are set up at the
1526 same time, in which case we want to make sure we don't
1527 interfere with that */
1528 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(so
)))
1531 if (!(name
= get_name(so
->proplist
, "source-input")))
1534 if ((e
= read_entry(u
, name
))) {
1535 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1536 pa_source_output_move_to(so
, source
, TRUE
);
1547 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1554 pa_assert(u
->on_rescue
&& u
->restore_device
);
1556 /* There's no point in doing anything if the core is shut down anyway */
1557 if (c
->state
== PA_CORE_SHUTDOWN
)
1560 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1567 if (!(name
= get_name(si
->proplist
, "sink-input")))
1570 if ((e
= read_entry(u
, name
))) {
1572 if (e
->device_valid
) {
1575 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) &&
1577 PA_SINK_IS_LINKED(pa_sink_get_state(d
)))
1578 pa_sink_input_move_to(si
, d
, TRUE
);
1590 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1591 pa_source_output
*so
;
1597 pa_assert(u
->on_rescue
&& u
->restore_device
);
1599 /* There's no point in doing anything if the core is shut down anyway */
1600 if (c
->state
== PA_CORE_SHUTDOWN
)
1603 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1607 if (so
->direct_on_input
)
1613 if (!(name
= get_name(so
->proplist
, "source-output")))
1616 if ((e
= read_entry(u
, name
))) {
1618 if (e
->device_valid
) {
1621 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) &&
1623 PA_SOURCE_IS_LINKED(pa_source_get_state(d
)))
1624 pa_source_output_move_to(so
, d
, TRUE
);
1636 #define EXT_VERSION 1
1638 static void apply_entry(struct userdata
*u
, const char *name
, struct entry
*e
) {
1640 pa_source_output
*so
;
1647 PA_IDXSET_FOREACH(si
, u
->core
->sink_inputs
, idx
) {
1651 if (!(n
= get_name(si
->proplist
, "sink-input")))
1654 if (!pa_streq(name
, n
)) {
1660 if (u
->restore_volume
&& e
->volume_valid
) {
1664 pa_log_info("Restoring volume for sink input %s.", name
);
1665 pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
);
1666 pa_sink_input_set_volume(si
, &v
, TRUE
, FALSE
);
1669 if (u
->restore_muted
&& e
->muted_valid
) {
1670 pa_log_info("Restoring mute state for sink input %s.", name
);
1671 pa_sink_input_set_mute(si
, e
->muted
, TRUE
);
1674 if (u
->restore_device
&&
1676 (s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1678 pa_log_info("Restoring device for stream %s.", name
);
1679 pa_sink_input_move_to(si
, s
, TRUE
);
1683 PA_IDXSET_FOREACH(so
, u
->core
->source_outputs
, idx
) {
1687 if (!(n
= get_name(so
->proplist
, "source-output")))
1690 if (!pa_streq(name
, n
)) {
1696 if (u
->restore_device
&&
1698 (s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1700 pa_log_info("Restoring device for stream %s.", name
);
1701 pa_source_output_move_to(so
, s
, TRUE
);
1707 static void dump_database(struct userdata
*u
) {
1711 done
= !pa_database_first(u
->database
, &key
, NULL
);
1718 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1720 name
= pa_xstrndup(key
.data
, key
.size
);
1721 pa_datum_free(&key
);
1723 if ((e
= read_entry(u
, name
))) {
1725 pa_log("name=%s", name
);
1726 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1727 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1728 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1729 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1740 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1743 pa_tagstruct
*reply
= NULL
;
1752 if (pa_tagstruct_getu32(t
, &command
) < 0)
1755 reply
= pa_tagstruct_new(NULL
, 0);
1756 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1757 pa_tagstruct_putu32(reply
, tag
);
1760 case SUBCOMMAND_TEST
: {
1761 if (!pa_tagstruct_eof(t
))
1764 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1768 case SUBCOMMAND_READ
: {
1772 if (!pa_tagstruct_eof(t
))
1775 done
= !pa_database_first(u
->database
, &key
, NULL
);
1782 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1784 name
= pa_xstrndup(key
.data
, key
.size
);
1785 pa_datum_free(&key
);
1787 if ((e
= read_entry(u
, name
))) {
1791 pa_tagstruct_puts(reply
, name
);
1792 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1793 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1794 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1795 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1808 case SUBCOMMAND_WRITE
: {
1810 pa_bool_t apply_immediately
= FALSE
;
1812 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1813 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1816 if (mode
!= PA_UPDATE_MERGE
&&
1817 mode
!= PA_UPDATE_REPLACE
&&
1818 mode
!= PA_UPDATE_SET
)
1821 if (mode
== PA_UPDATE_SET
) {
1823 struct dbus_entry
*de
;
1826 PA_HASHMAP_FOREACH(de
, u
->dbus_entries
, state
) {
1827 send_entry_removed_signal(de
);
1828 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
1831 pa_database_clear(u
->database
);
1834 while (!pa_tagstruct_eof(t
)) {
1835 const char *name
, *device
;
1844 entry
.version
= ENTRY_VERSION
;
1846 if (pa_tagstruct_gets(t
, &name
) < 0 ||
1847 pa_tagstruct_get_channel_map(t
, &entry
.channel_map
) ||
1848 pa_tagstruct_get_cvolume(t
, &entry
.volume
) < 0 ||
1849 pa_tagstruct_gets(t
, &device
) < 0 ||
1850 pa_tagstruct_get_boolean(t
, &muted
) < 0)
1853 if (!name
|| !*name
)
1856 entry
.volume_valid
= entry
.volume
.channels
> 0;
1858 if (entry
.volume_valid
)
1859 if (!pa_cvolume_compatible_with_channel_map(&entry
.volume
, &entry
.channel_map
))
1862 entry
.muted
= muted
;
1863 entry
.muted_valid
= TRUE
;
1866 pa_strlcpy(entry
.device
, device
, sizeof(entry
.device
));
1867 entry
.device_valid
= !!entry
.device
[0];
1869 if (entry
.device_valid
&&
1870 !pa_namereg_is_valid_name(entry
.device
))
1874 old
= read_entry(u
, name
);
1877 key
.data
= (char*) name
;
1878 key
.size
= strlen(name
);
1881 data
.size
= sizeof(entry
);
1883 if (pa_database_set(u
->database
, &key
, &data
, mode
== PA_UPDATE_REPLACE
) == 0) {
1885 struct dbus_entry
*de
;
1888 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1890 if ((old
->device_valid
!= entry
.device_valid
)
1891 || (entry
.device_valid
&& !pa_streq(entry
.device
, old
->device
)))
1892 send_device_updated_signal(de
, &entry
);
1894 if ((old
->volume_valid
!= entry
.volume_valid
)
1895 || (entry
.volume_valid
1896 && (!pa_cvolume_equal(&entry
.volume
, &old
->volume
) || !pa_channel_map_equal(&entry
.channel_map
, &old
->channel_map
))))
1897 send_volume_updated_signal(de
, &entry
);
1899 if (!old
->muted_valid
|| (entry
.muted
!= old
->muted
))
1900 send_mute_updated_signal(de
, &entry
);
1903 de
= dbus_entry_new(u
, name
);
1904 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
));
1905 send_new_entry_signal(de
);
1909 if (apply_immediately
)
1910 apply_entry(u
, name
, &entry
);
1924 case SUBCOMMAND_DELETE
:
1926 while (!pa_tagstruct_eof(t
)) {
1930 struct dbus_entry
*de
;
1933 if (pa_tagstruct_gets(t
, &name
) < 0)
1937 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
1938 send_entry_removed_signal(de
);
1939 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
1943 key
.data
= (char*) name
;
1944 key
.size
= strlen(name
);
1946 pa_database_unset(u
->database
, &key
);
1953 case SUBCOMMAND_SUBSCRIBE
: {
1957 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
1958 !pa_tagstruct_eof(t
))
1962 pa_idxset_put(u
->subscribed
, c
, NULL
);
1964 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
1973 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
1979 pa_tagstruct_free(reply
);
1984 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
1989 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
1993 int pa__init(pa_module
*m
) {
1994 pa_modargs
*ma
= NULL
;
1998 pa_source_output
*so
;
2000 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
2008 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
2009 pa_log("Failed to parse module arguments");
2013 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
2014 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
2015 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
2016 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
2017 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
2018 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
2022 if (!restore_muted
&& !restore_volume
&& !restore_device
)
2023 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
2025 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
2028 u
->restore_device
= restore_device
;
2029 u
->restore_volume
= restore_volume
;
2030 u
->restore_muted
= restore_muted
;
2031 u
->on_hotplug
= on_hotplug
;
2032 u
->on_rescue
= on_rescue
;
2033 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
2035 u
->protocol
= pa_native_protocol_get(m
->core
);
2036 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
2038 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
);
2040 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
2042 if (restore_device
) {
2043 /* A little bit earlier than module-intended-roles ... */
2044 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
);
2045 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
);
2048 if (restore_device
&& on_hotplug
) {
2049 /* A little bit earlier than module-intended-roles ... */
2050 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
);
2051 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
);
2054 if (restore_device
&& on_rescue
) {
2055 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
2056 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
);
2057 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
);
2060 if (restore_volume
|| restore_muted
)
2061 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
);
2063 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
2066 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
2067 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
2072 pa_log_info("Sucessfully opened database file '%s'.", fname
);
2076 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2077 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2079 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2080 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2082 /* Create the initial dbus entries. */
2083 done
= !pa_database_first(u
->database
, &key
, NULL
);
2087 struct dbus_entry
*de
;
2089 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2091 name
= pa_xstrndup(key
.data
, key
.size
);
2092 pa_datum_free(&key
);
2094 de
= dbus_entry_new(u
, name
);
2095 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) >= 0);
2103 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2104 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2106 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2107 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2109 pa_modargs_free(ma
);
2116 pa_modargs_free(ma
);
2122 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2123 struct dbus_entry
*de
= p
;
2127 dbus_entry_free(de
);
2131 void pa__done(pa_module
*m
) {
2136 if (!(u
= m
->userdata
))
2140 if (u
->dbus_protocol
) {
2141 pa_assert(u
->dbus_entries
);
2143 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2144 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2146 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2148 pa_dbus_protocol_unref(u
->dbus_protocol
);
2152 if (u
->subscription
)
2153 pa_subscription_free(u
->subscription
);
2155 if (u
->sink_input_new_hook_slot
)
2156 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2157 if (u
->sink_input_fixate_hook_slot
)
2158 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2159 if (u
->source_output_new_hook_slot
)
2160 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2162 if (u
->sink_put_hook_slot
)
2163 pa_hook_slot_free(u
->sink_put_hook_slot
);
2164 if (u
->source_put_hook_slot
)
2165 pa_hook_slot_free(u
->source_put_hook_slot
);
2167 if (u
->sink_unlink_hook_slot
)
2168 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2169 if (u
->source_unlink_hook_slot
)
2170 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2172 if (u
->connection_unlink_hook_slot
)
2173 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2175 if (u
->save_time_event
)
2176 u
->core
->mainloop
->time_free(u
->save_time_event
);
2179 pa_database_close(u
->database
);
2182 pa_native_protocol_remove_ext(u
->protocol
, m
);
2183 pa_native_protocol_unref(u
->protocol
);
2187 pa_idxset_free(u
->subscribed
, NULL
, NULL
);